using System.Security.Claims; using System.Text.Encodings.Web; using Femto.Api.Sessions; using Femto.Common; using Femto.Modules.Auth.Application; using Femto.Modules.Auth.Application.Interface.ValidateSession; using Femto.Modules.Auth.Errors; using Microsoft.AspNetCore.Authentication; using Microsoft.Extensions.Options; using Microsoft.OpenApi.Extensions; namespace Femto.Api.Auth; internal class SessionAuthenticationHandler( IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, IAuthModule authModule, CurrentUserContext currentUserContext, IOptions cookieOptions ) : AuthenticationHandler(options, logger, encoder) { protected override async Task HandleAuthenticateAsync() { var sessionId = this.Request.Cookies["session"]; if (string.IsNullOrWhiteSpace(sessionId)) return AuthenticateResult.NoResult(); try { var result = await authModule.Command(new ValidateSessionCommand(sessionId)); var claims = new List { new(ClaimTypes.Name, result.User.Username), new("sub", result.User.Id.ToString()), new("user_id", result.User.Id.ToString()), }; claims.AddRange( result.User.Roles .Select(role => new Claim(ClaimTypes.Role, role.ToString())) ); var identity = new ClaimsIdentity(claims, this.Scheme.Name); var principal = new ClaimsPrincipal(identity); this.Context.SetSession(result.Session, cookieOptions.Value); currentUserContext.CurrentUser = new CurrentUser(result.User.Id, result.User.Username); return AuthenticateResult.Success( new AuthenticationTicket(principal, this.Scheme.Name) ); } catch (InvalidSessionError) { return AuthenticateResult.Fail("Invalid session"); } } }