Flux d'execution
Diagrammes de sequence des flux metier principaux - login, registration, refresh token, audit
Flux d'execution
Flux de connexion (Login)
Cas standard (sans 2FA)
mermaid
sequenceDiagram
participant C as Client
participant E as LoginEndpoint
participant M as MediatR
participant V as ValidationBehavior
participant A as AuditCommandBehavior
participant H as LoginCommandHandler
participant UM as UserManager
participant SM as SignInManager
participant TB as AuthTokenResponseBuilder
participant SS as SessionService
participant DB as IdentityContext
C->>E: POST /api/v1/identity/auth/login
Note right of C: {email, password, deviceId}
E->>M: Send(LoginCommand)
M->>V: Pipeline: Validation
V->>V: Valider email, password, deviceId
V->>A: Pipeline: Audit
A->>H: Handle(command, ct)
H->>UM: FindByEmailAsync(normalizedEmail)
UM-->>H: User
alt Utilisateur non trouve
H-->>E: UnauthorizedError
end
H->>SM: CheckPasswordSignInAsync(user, password, lockout: true)
SM-->>H: SignInResult
alt Lockout
H-->>E: AccountLockedError(lockoutEnd)
end
alt Mot de passe invalide
H-->>E: UnauthorizedError
end
alt Compte inactif ou email non confirme
H-->>E: UnauthorizedError
end
H->>TB: BuildAsync(user, device, ct)
TB->>SS: CreateSessionAsync(sessionData)
SS->>DB: Persister UserSession
TB-->>H: AuthTokensResponse
H->>UM: UpdateAsync(user)
Note right of H: User.RecordLogin() met a jour LastLoginAt
H-->>A: AuthTokensResponse
A->>A: Emettre AuditEventV1 (success)
A-->>E: AuthTokensResponse
E-->>C: 200 OK {accessToken, refreshToken, user}Cas avec 2FA active
mermaid
sequenceDiagram
participant C as Client
participant H as LoginCommandHandler
participant TF as TwoFactorService
participant TC as TwoFactorChallengeService
C->>H: LoginCommand (email, password, deviceId)
Note right of H: Apres verification du mot de passe...
H->>TF: IsTwoFactorEnabledAsync(userId)
TF-->>H: true
H->>TC: CreateChallengeAsync(userId)
TC-->>H: challengeToken
H-->>C: TwoFactorRequiredError(challengeToken)
Note right of C: Le client doit maintenant<br/>appeler /auth/2fa/login
C->>H: Login2FaCommand (challengeToken, code, deviceId)
H->>TC: ValidateAndConsumeAsync(challengeToken)
TC-->>H: userId
H->>TF: ValidateTwoFactorAsync(userId, code)
TF-->>H: true
Note right of H: Construction des tokens...
H-->>C: 200 OK {accessToken, refreshToken, user}Flux d'inscription (Register)
mermaid
sequenceDiagram
participant C as Client
participant E as RegisterEndpoint
participant M as MediatR
participant V as ValidationBehavior
participant H as RegisterCommandHandler
participant RS as UserRegistrationService
participant UM as UserManager
participant TB as AuthTokenResponseBuilder
participant MQ as MediatR (Notification)
participant MSG as SendEmailCommandHandler
participant SMTP as SMTP Server
C->>E: POST /api/v1/identity/auth/register
Note right of C: {email, password, confirmPassword, deviceId}
E->>M: Send(RegisterCommand)
M->>V: Validation
V->>V: Valider email, password, confirmPassword, deviceId
V->>H: Handle(command, ct)
H->>RS: CreateUserWithPasswordAsync(profile, password)
RS->>UM: FindByEmailAsync(normalizedEmail)
alt Email deja utilise
RS-->>H: DuplicateEmail
H-->>C: 409 Conflict
end
RS->>UM: CreateAsync(user, password)
UM-->>RS: IdentityResult
alt Mot de passe trop faible
RS-->>H: WeakPassword(errors)
H-->>C: 400 Bad Request
end
RS->>UM: AddToRoleAsync(user, "User")
RS-->>H: Success(user, roles)
H->>TB: BuildAsync(user, device, ct)
Note right of TB: Cree la session + genere les tokens
TB-->>H: AuthTokensResponse
H-->>C: 200 OK {accessToken, refreshToken, user}
Note over MQ,SMTP: Notification asynchrone (meme processus)
MQ->>MSG: SendConfirmationEmailOnUserRegistered
MSG->>MSG: Generer OTP
MSG->>SMTP: Envoyer email de confirmationFlux de rafraichissement de token (Refresh Token)
Cas standard (rotation reussie)
mermaid
sequenceDiagram
participant C as Client
participant E as RefreshTokenEndpoint
participant H as RefreshTokenCommandHandler
participant SR as SessionReader
participant SW as SessionWriter
participant TS as TokenService
participant UM as UserManager
participant DB as IdentityContext
C->>E: POST /api/v1/identity/auth/refresh
Note right of C: {refreshToken, deviceId}
E->>H: Handle(RefreshTokenCommand, ct)
H->>H: HashedToken.FromRaw(refreshToken, pepper)
Note right of H: Hash HMAC-SHA256 du token recu
H->>SR: FindByRefreshTokenHashAsync(tokenHash)
SR-->>H: UserSession
H->>H: Verifier: session non revoquee
H->>H: Verifier: session non expiree
H->>H: Verifier: binding IP/DeviceId
H->>UM: FindByIdAsync(session.UserId)
UM-->>H: User (actif)
H->>TS: GenerateAccessToken(claims)
TS-->>H: newAccessToken
H->>TS: GenerateRefreshToken()
TS-->>H: newRefreshToken
H->>H: HashedToken.FromRaw(newRefreshToken, pepper)
H->>SW: RotateTokenAsync(session, newHash)
Note right of SW: Ancien hash -> PreviousRefreshTokenHash<br/>Nouveau hash -> RefreshTokenHash
SW->>DB: SaveChangesAsync()
SW-->>H: true
H-->>C: 200 OK {newAccessToken, newRefreshToken, user}Detection de replay
mermaid
sequenceDiagram
participant A as Attaquant
participant L as Client legitime
participant H as RefreshTokenHandler
participant SR as SessionReader
participant SW as SessionWriter
participant ED as EventDispatcher
Note over A,L: Scenario: l'attaquant a vole un refresh token
L->>H: RefreshTokenCommand(token_v1)
H->>SR: FindByRefreshTokenHashAsync(hash_v1)
SR-->>H: Session (RefreshTokenHash = hash_v1)
H->>SW: RotateTokenAsync(session, hash_v2)
Note right of SW: hash_v1 -> PreviousRefreshTokenHash<br/>hash_v2 -> RefreshTokenHash
H-->>L: 200 OK {token_v2}
Note over A: L'attaquant tente d'utiliser<br/>le token vole (token_v1)
A->>H: RefreshTokenCommand(token_v1)
H->>SR: FindByRefreshTokenHashAsync(hash_v1)
SR-->>H: null (plus le token courant)
H->>SR: FindByPreviousTokenHashAsync(hash_v1)
SR-->>H: Session trouvee!
Note right of H: Token precedent reutilise<br/>= REPLAY DETECTE
H->>H: Verifier grace period (30s)
Note right of H: Si > 30s depuis rotation
H->>ED: TokenReplayDetectedEvent
H->>SW: RevokeAllUserSessionsAsync(userId, ReplayDetected)
Note right of SW: TOUTES les sessions revoquees<br/>Le client legitime devra se reconnecter
H-->>A: 401 UnauthorizedFlux d'audit
mermaid
sequenceDiagram
participant C as Client HTTP
participant MW as AuditHttpMiddleware
participant EP as Endpoint
participant AB as AuditCommandBehavior
participant H as Handler
participant AE as AuditEmitter
participant CE as ConsumeAuditEvent
participant AW as AuditLogWriter
participant DB as AuditContext
participant SH as AuditHub (SignalR)
participant AD as Admin Dashboard
C->>MW: HTTP Request
MW->>MW: Capturer contexte (IP, UA, corrID)
MW->>EP: Passer au suivant
EP->>AB: MediatR Pipeline
AB->>H: Handler metier
H-->>AB: Resultat
AB->>AE: EmitAsync(AuditEventV1 - command)
AE->>CE: MediatR Notification
EP-->>MW: HTTP Response
MW->>AE: EmitAsync(AuditEventV1 - http)
AE->>CE: MediatR Notification
Note over CE,AD: Pour chaque notification
CE->>AW: WriteAsync(auditEvent)
AW->>DB: AddAsync + SaveChangesAsync
AW->>SH: SendAsync("AuditLogInserted", summary)
SH->>AD: Temps reel via WebSocket
Note right of AD: L'admin voit les logs<br/>en temps reelFlux d'envoi d'email
mermaid
sequenceDiagram
participant ID as Module Identity
participant M as MediatR
participant PB as MessagingPersistenceBehavior
participant EH as SendEmailCommandHandler
participant TR as MjmlTemplateRenderer
participant ES as SmtpEmailSender
participant DB as MessagingContext
participant SMTP as Serveur SMTP
ID->>M: Send(SendEmailCommand(EmailMessage))
M->>PB: Pipeline Behavior
PB->>DB: Creer SentMessage (status: Pending)
PB->>DB: SaveChangesAsync()
PB->>EH: Handle(SendEmailCommand, ct)
EH->>TR: Render("confirm-email", variables)
TR-->>EH: HTML responsive
EH->>ES: SendAsync(to, subject, htmlBody, replyTo)
ES->>SMTP: Envoyer email via MailKit
alt Envoi reussi
SMTP-->>ES: OK
ES-->>EH: OK
EH-->>PB: Unit.Value
PB->>PB: SentMessage.Status = Sent
PB->>PB: SentMessage.SentAt = UtcNow
else Envoi echoue
SMTP-->>ES: Erreur
ES-->>EH: Exception
EH-->>PB: Exception
PB->>PB: SentMessage.Status = Failed
PB->>PB: SentMessage.ErrorMessage = exception.Message
end
PB->>DB: SaveChangesAsync()
Note right of DB: Statut final toujours persisteFlux d'authentification sociale
mermaid
sequenceDiagram
participant C as Client
participant H as SocialLoginHandler
participant STV as SocialTokenValidator
participant UM as UserManager
participant RS as UserRegistrationService
participant PL as ProviderLinkingService
participant TB as AuthTokenResponseBuilder
C->>H: SocialLoginCommand (provider, token, deviceId)
H->>STV: ValidateAsync(provider, token)
STV-->>H: SocialUserInfo (email, name, picture)
H->>UM: FindByLoginAsync(provider, providerId)
alt Compte deja lie
UM-->>H: User existant
H->>TB: BuildAsync(user, device)
H-->>C: {tokens, isNewAccount: false}
else Premier login social
H->>UM: FindByEmailAsync(email)
alt Email existe deja (compte local)
UM-->>H: User existant
H->>PL: LinkAsync(user, provider, providerKey)
H->>TB: BuildAsync(user, device)
H-->>C: {tokens, isNewAccount: false}
else Nouvel utilisateur
H->>RS: CreateUserWithExternalProviderAsync(profile)
RS-->>H: Success(newUser, roles)
H->>PL: LinkAsync(newUser, provider, providerKey)
H->>TB: BuildAsync(newUser, device)
H-->>C: {tokens, isNewAccount: true}
end
end