Handler.cs 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. using SharedKernel;
  2. using SharedKernel.Results;
  3. using Application.Abstractions.Authentication;
  4. using Application.Abstractions.Data;
  5. using MediatR;
  6. using Microsoft.EntityFrameworkCore;
  7. using Microsoft.Extensions.Options;
  8. using RefreshTokenEntity = Domain.Entities.Members.RefreshToken;
  9. namespace Application.Features.Auth.Login;
  10. internal sealed class Handler(
  11. IAppDbContext db,
  12. IJwtTokenProvider jwtTokenProvider,
  13. IOptions<AppSettings> options
  14. ) : IRequestHandler<Command, Result<Response>> {
  15. private readonly AppSettings.JwtSection _jwt = options.Value.JWT;
  16. public async Task<Result<Response>> Handle(Command request, CancellationToken ct)
  17. {
  18. // 유효성 검사
  19. if (string.IsNullOrWhiteSpace(request.Email))
  20. {
  21. return Result.Failure<Response>(Error.Problem("Auth.EmailRequired", "이메일은 필수입니다."));
  22. }
  23. if (string.IsNullOrWhiteSpace(request.Password))
  24. {
  25. return Result.Failure<Response>(Error.Problem("Auth.PasswordRequired", "비밀번호는 필수입니다."));
  26. }
  27. // Member 조회 (비밀번호 검증을 위해 Tracking 모드)
  28. var email = request.Email.Trim().ToLower();
  29. var member = await db.Member.FirstOrDefaultAsync(m => m.Email == email, ct);
  30. if (member is null)
  31. {
  32. return Result.Failure<Response>(Error.Unauthorized("Auth.InvalidCredentials", "이메일 또는 비밀번호가 올바르지 않습니다."));
  33. }
  34. // 비밀번호 검증
  35. if (!member.VerifyPassword(request.Password))
  36. {
  37. return Result.Failure<Response>(Error.Unauthorized("Auth.InvalidCredentials", "이메일 또는 비밀번호가 올바르지 않습니다."));
  38. }
  39. // JWT 토큰 생성
  40. var accessToken = jwtTokenProvider.CreateAccessToken(member.ID, member.Email, member.Name);
  41. var refreshToken = jwtTokenProvider.CreateRefreshToken();
  42. var expiresAt = DateTime.UtcNow.AddMinutes(_jwt.AccessTokenExpiration);
  43. // RefreshToken 저장
  44. var refreshTokenEntity = RefreshTokenEntity.Create(
  45. member.ID,
  46. refreshToken,
  47. DateTime.UtcNow.AddDays(_jwt.RefreshTokenExpiration)
  48. );
  49. await db.RefreshToken.AddAsync(refreshTokenEntity, ct);
  50. await db.SaveChangesAsync(ct);
  51. return Result.Success(new Response(accessToken, refreshToken, expiresAt));
  52. }
  53. }