namespace TaxBaik.Web.Services; using System.Security.Claims; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Identity; using TaxBaik.Application.Services; using TaxBaik.Domain.Entities; public class PortalAuthService( IHttpContextAccessor httpContextAccessor, PortalUserService portalUserService) { private static readonly PasswordHasher Hasher = new(); public async Task SignInAsync(string email, string password, CancellationToken ct = default) { var httpContext = httpContextAccessor.HttpContext ?? throw new InvalidOperationException("HTTP context is unavailable."); var user = await portalUserService.GetByEmailAsync(email, ct); if (user is null) return false; if (string.IsNullOrWhiteSpace(user.PasswordHash)) return false; var verify = Hasher.VerifyHashedPassword(user, user.PasswordHash, password); if (verify == PasswordVerificationResult.Failed) return false; var claims = new List { new(ClaimTypes.NameIdentifier, user.Id.ToString()), new(ClaimTypes.Name, user.Name), new(ClaimTypes.Email, user.Email), new("portal_user_id", user.Id.ToString()) }; if (user.ClientId.HasValue) claims.Add(new("client_id", user.ClientId.Value.ToString())); var identity = new ClaimsIdentity(claims, PortalAuthDefaults.Scheme); var principal = new ClaimsPrincipal(identity); await httpContext.SignInAsync( PortalAuthDefaults.Scheme, principal, new AuthenticationProperties { IsPersistent = true }); return true; } public static string HashPassword(string password) { var tempUser = new PortalUser(); return Hasher.HashPassword(tempUser, password); } public async Task SignOutAsync() { var httpContext = httpContextAccessor.HttpContext ?? throw new InvalidOperationException("HTTP context is unavailable."); await httpContext.SignOutAsync(PortalAuthDefaults.Scheme); } }