Authentication
Gerçek credential doğrulayıcınızı handshake scope’una bağlayın ve bağlantıya doğrulanmış bir Principal kazandırın.
Lily'nin authentication desteği tek global identity middleware yuvasıdır. Middleware 101 öncesinde çalışır, scoped servis çözebilir ve doğrulama sonucunu bağlantı kimliğine dönüştürür. JWT, OIDC sağlayıcısı veya session store uygulamanızın entegrasyonudur.
Gerçek verifier’ı bağlayın#
Aşağıdaki örnek Authorization header gönderebilen servis/CLI istemcileri içindir. SessionVerifier bir uygulama interface'idir; bu bildirim tek başına authentication kurulumu değildir. Gerçek implementasyonu [DI bağımlılıkları] yerine DI kaydıyla sisteme dahil edin ve ServiceTrait uygulayın. Interface kaydı #[service(interface = dyn SessionVerifier, lifetime = "Scoped")] veya uygun Singleton lifetime kullanır.
use std::sync::Arc;
use lilyrs::websocket::{AuthenticatedWebSocketIdentity, ExecutionCancellation, Extensions,
HeaderValue, Principal, WsAppBuilder, async_trait};
use lilyrs::websocket::middleware::{MiddlewareDescriptor, MiddlewareErrorCode, MiddlewareKind,
WebSocketIdentity, WebSocketIdentityMiddleware, WsHandshakeExchange,
WsHandshakeRejection, WsMiddlewareInitError};
#[derive(Clone)]
pub struct TenantId(pub String);
pub struct VerifiedSession {
pub principal: Principal,
pub tenant: TenantId,
pub expires_at: tokio::time::Instant,
}
// Uygulama bu interface'i gerçek doğrulayıcısına DI ile bağlar.
// İmza, issuer/audience, süre ve session iptali kontrolleri bu servise aittir.
#[async_trait]
pub trait SessionVerifier: Send + Sync {
async fn verify(&self, authorization: &str) -> Option<VerifiedSession>;
}
pub struct SessionIdentity;
fn unauthorized() -> WsHandshakeRejection {
WsHandshakeRejection::unauthorized(
MiddlewareErrorCode::new("AUTH_REQUIRED").expect("sabit kod"),
HeaderValue::from_static("Bearer"),
).expect("geçerli challenge")
}
fn unavailable() -> WsHandshakeRejection {
WsHandshakeRejection::try_new(503,
MiddlewareErrorCode::new("AUTH_UNAVAILABLE").expect("sabit kod"),
).expect("geçerli durum")
}
#[async_trait]
impl WebSocketIdentityMiddleware for SessionIdentity {
async fn new(_: Arc<Extensions>) -> Result<Self, WsMiddlewareInitError> { Ok(Self) }
fn descriptor(&self) -> MiddlewareDescriptor {
MiddlewareDescriptor::new("session_identity", MiddlewareKind::WebSocketHandshake)
}
async fn identify(&self, exchange: &mut WsHandshakeExchange,
cancellation: ExecutionCancellation) -> Result<WebSocketIdentity, WsHandshakeRejection>
{
let authorization = exchange.request().headers().get_custom_header("authorization")
.ok_or_else(unauthorized)?.to_owned();
let verifier = exchange.service::<dyn SessionVerifier>().await
.map_err(|_| unavailable())?;
let verified = tokio::select! {
biased;
_ = cancellation.cancelled() => return Err(unavailable()),
result = verifier.verify(&authorization) => result.ok_or_else(unauthorized)?,
};
let authenticated = AuthenticatedWebSocketIdentity::try_new(verified.principal)
.map_err(|_| unavailable())?.expires_at(verified.expires_at);
let mut identity = WebSocketIdentity::authenticated(authenticated);
identity.insert_connection_local(verified.tenant).map_err(|_| unavailable())?;
Ok(identity)
}
}
pub fn with_identity(builder: WsAppBuilder) -> WsAppBuilder {
builder.identity_middleware::<SessionIdentity>()
}Örneği src/identity.rs olarak kaydedin. Builder'ı identity::with_identity(builder) üzerinden geçirin veya .identity_middleware::<identity::SessionIdentity>() çağırın. İkisini birlikte kullanmayın; app başına tek identity middleware vardır.
Doğrulama sorumluluğu#
Verifier imza, issuer, audience, süre ve session iptali gibi credential kurallarını uygular. Principal yalnızca bu kontrolden sonra oluşturulur. Header'ı parse etmek veya bir token'ın subject alanını okumak doğrulamanın yerine geçmez.
Eksik/geçersiz credential 401, kullanılamayan verifier 503 ile reddedilir. 401 geçerli Bearer challenge taşır. Provider'ın iç hata metni public response'a kopyalanmaz. Cancellation geldiğinde örnek yeni doğrulama sonucu beklemeyi bırakır; gerçek verifier kendi I/O sahipliğini ve iptal sözleşmesini de düzenlemelidir.
Bağlantıya ne taşınır?#
Handshake scope'undaki verifier taşınmaz. Doğrulanmış Principal, isteğe bağlı monotonic expiry ve owned TenantId taşınır. Connection locals en fazla 32 typed değer içerir. PrincipalId boş olmayan, çevresinde whitespace ve içinde kontrol karakteri bulunmayan, en fazla 256 UTF-8 byte'lık exact kimliktir.
Tenant'lar aynı subject değerini kullanıyorsa namespace ve recipient anahtar politikasını siz ayırın; Lily tenant anlamını kendiliğinden çıkarmaz. Her mesaj kimliğin immutable snapshot'ını alır. Rol, scope ve nesne yetkisini guard ile uygulayın.
Public namespace ve browser#
Aynı app public ve private namespace taşıyorsa identity middleware exact namespace'e göre dallanabilir; public olan için WebSocketIdentity::anonymous() döner. Anonymous bağlantıda required Principal extraction başarılı olmaz; bilinçli optional erişim için Option<Principal> kullanın.
Tarayıcı constructor'ı keyfi Authorization header almaz. Browser login ve cookie doğrulaması için session/CSRF akışını izleyin. Kimlik yenileme ve süre dolmasını identity lifecycle sayfası açıklar.
Bu sayfanın kaynakları v0.1.0
Anlatım, incelenen framework commit’ine dayanır.