using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using RT.Application.Services.Contract; using RT.Domain.DTOs.Auth; using RT.Domain.Entities; using RT.Infrastructure.Data; using RT.Domain.Identity; namespace RT.Application.Services.Implementation; public class AuthService( UserManager userManager, ITokenService tokenService, AppDbContext db) : IAuthService { public async Task LoginAsync(LoginRequestDto dto, CancellationToken ct = default) { var user = await userManager.FindByEmailAsync(dto.Email) ?? throw new UnauthorizedAccessException("Invalid credentials."); if (!await userManager.CheckPasswordAsync(user, dto.Password)) throw new UnauthorizedAccessException("Invalid credentials."); return await BuildResponseAsync(user, ct); } public async Task RefreshAsync(RefreshRequestDto dto, CancellationToken ct = default) { var stored = await db.RefreshTokens.FirstOrDefaultAsync(r => r.Token == dto.RefreshToken, ct) ?? throw new UnauthorizedAccessException("Invalid refresh token."); if (stored.IsRevoked) throw new UnauthorizedAccessException("Refresh token revoked."); if (stored.ExpiresAt < DateTime.UtcNow) throw new UnauthorizedAccessException("Refresh token expired."); stored.IsRevoked = true; await db.SaveChangesAsync(ct); var user = await userManager.FindByIdAsync(stored.UserId) ?? throw new UnauthorizedAccessException("User not found."); return await BuildResponseAsync(user, ct); } public async Task RevokeAsync(RefreshRequestDto dto, CancellationToken ct = default) { var stored = await db.RefreshTokens.FirstOrDefaultAsync(r => r.Token == dto.RefreshToken, ct); if (stored is null || stored.IsRevoked) return; stored.IsRevoked = true; await db.SaveChangesAsync(ct); } private async Task BuildResponseAsync(ApplicationUser user, CancellationToken ct) { var (token, expiresAt) = tokenService.GenerateToken(user.Id, user.Email!, user.UserName!); var (refreshToken, refreshExpiresAt) = tokenService.GenerateRefreshToken(); db.RefreshTokens.Add(new RefreshToken { UserId = user.Id, Token = refreshToken, ExpiresAt = refreshExpiresAt, }); await db.SaveChangesAsync(ct); return new LoginResponseDto(token, expiresAt, refreshToken, refreshExpiresAt, user.MustChangePassword); } }