Handler.cs 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  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.RefreshToken;
  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. if (string.IsNullOrWhiteSpace(request.RefreshToken))
  19. {
  20. return Result.Failure<Response>(Error.Problem("Auth.TokenRequired", "리프레시 토큰은 필수입니다."));
  21. }
  22. // 기존 RefreshToken 조회
  23. var existingToken = await db.RefreshToken.Include(x => x.Member).FirstOrDefaultAsync(x => x.Token == request.RefreshToken, ct);
  24. if (existingToken is null)
  25. {
  26. return Result.Failure<Response>(Error.NotFound("Auth.TokenNotFound", "유효하지 않은 리프레시 토큰입니다."));
  27. }
  28. if (!existingToken.IsActive)
  29. {
  30. return Result.Failure<Response>(Error.Problem("Auth.TokenExpired", "만료되었거나 취소된 리프레시 토큰입니다."));
  31. }
  32. if (existingToken.Member is null)
  33. {
  34. return Result.Failure<Response>(Error.NotFound("Auth.MemberNotFound", "회원 정보를 찾을 수 없습니다."));
  35. }
  36. var member = existingToken.Member;
  37. // 기존 토큰 폐기
  38. existingToken.Revoke();
  39. // 새 토큰 생성
  40. var accessToken = jwtTokenProvider.CreateAccessToken(member.ID, member.Email, member.Name);
  41. var newRefreshToken = jwtTokenProvider.CreateRefreshToken();
  42. var expiresAt = DateTime.UtcNow.AddMinutes(_jwt.AccessTokenExpiration);
  43. // 새 RefreshToken 저장
  44. var refreshTokenEntity = RefreshTokenEntity.Create(
  45. member.ID,
  46. newRefreshToken,
  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(
  52. accessToken, newRefreshToken, expiresAt
  53. ));
  54. }
  55. }