Files
the-biergarten-app/docs/website/diagrams-src/auth/confirm-user.puml

110 lines
3.4 KiB
Plaintext

@startuml confirm-user
!include ../../../pipeline/diagrams/biergarten-weizen-theme.puml
skinparam sequenceMessageAlign center
skinparam maxMessageSize 200
title User Authentication Flow - Confirm User
actor User
participant "API\nController" as API
participant "MediatR pipeline\n(ValidationBehavior)" as Mediator
box "Handler Layer" #F1F3EA
participant "ConfirmUserHandler" as ConfirmHandler
participant "UserManager<ApplicationUser>" as UserMgr
participant "TokenService" as TokenSvc
end box
box "Infrastructure Layer" #EBECE3
participant "JWT\nInfrastructure" as JWT
end box
box "Repository / Cross-slice" #DBEEDD
participant "DapperUserStore\n(IUserStore/IUserPasswordStore/\nIUserEmailStore)" as UserStore
end box
database "SQL Server" as DB
note over UserMgr
ASP.NET Core Identity's UserManager<TUser>
replaces the deleted AuthRepository: handlers
no longer issue SQL or call Argon2 directly,
they delegate to UserManager, which in turn
calls DapperUserStore (persistence) and
Argon2PasswordHasher (IPasswordHasher<TUser>).
end note
User -> API: POST /api/auth/confirm?token=<token>\n(requires Bearer access token)
activate API
API -> Mediator: Send(ConfirmUserCommand(token))
activate Mediator
Mediator -> ConfirmHandler: Handle(command)
activate ConfirmHandler
ConfirmHandler -> TokenSvc: ValidateConfirmationTokenAsync(token)
activate TokenSvc
TokenSvc -> JWT: Validate against confirmation\ntoken secret, extract userId
activate JWT
JWT --> TokenSvc: ValidatedToken or throws
deactivate JWT
TokenSvc --> ConfirmHandler: ValidatedToken
deactivate TokenSvc
alt Token invalid or expired
ConfirmHandler -> Mediator: throw UnauthorizedException
Mediator -> API: propagate
API -> User: 401 Unauthorized
else Token valid
ConfirmHandler -> UserMgr: FindByIdAsync(validatedToken.UserId)
activate UserMgr
UserMgr -> UserStore: FindByIdAsync(userId)
activate UserStore
UserStore -> DB: SELECT ...\nFROM dbo.UserAccount\nWHERE UserAccountID = @Id
activate DB
DB --> UserStore: row or null
deactivate DB
UserStore --> UserMgr: ApplicationUser or null
deactivate UserStore
UserMgr --> ConfirmHandler: ApplicationUser or null
deactivate UserMgr
alt User not found
ConfirmHandler -> Mediator: throw UnauthorizedException\n"User account not found"
Mediator -> API: propagate
API -> User: 401 Unauthorized
else User found
ConfirmHandler -> UserStore: SetEmailConfirmedAsync(user, true)
note right of UserStore
IUserEmailStore<ApplicationUser> is injected
directly into the handler (not via UserManager),
setting the confirmed flag in-memory here.
end note
ConfirmHandler -> UserMgr: UpdateAsync(user)
activate UserMgr
UserMgr -> UserStore: UpdateAsync(user)
activate UserStore
UserStore -> DB: UPDATE dbo.UserAccount SET ...
UserStore -> DB: INSERT INTO dbo.UserVerification\n(UserAccountId, VerificationDateTime)
note right of UserStore
Idempotent: skipped (duplicate-key
exception swallowed) if a verification
row already exists.
end note
UserStore --> UserMgr: IdentityResult.Success
deactivate UserStore
UserMgr --> ConfirmHandler: IdentityResult
deactivate UserMgr
ConfirmHandler --> Mediator: ConfirmationPayload(\n user.Id, DateTime.UtcNow)
deactivate ConfirmHandler
Mediator --> API: ConfirmationPayload
deactivate Mediator
API -> User: 200 OK\n{message: "User with ID {id} is confirmed.",\npayload: {...}}
end
end
deactivate API
@enduml