RefreshToken.cs 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. using System.ComponentModel.DataAnnotations;
  2. using System.ComponentModel.DataAnnotations.Schema;
  3. namespace Domain.Entities.Members;
  4. public class RefreshToken
  5. {
  6. [ForeignKey(nameof(MemberID))]
  7. public virtual Member? Member { get; private set; }
  8. [Key]
  9. public long ID { get; private set; }
  10. public int MemberID { get; private set; }
  11. public string Token { get; private set; } = default!;
  12. public DateTime ExpiresAt { get; private set; }
  13. public DateTime CreatedAt { get; private set; } = DateTime.UtcNow;
  14. public bool IsRevoked { get; private set; } = false;
  15. public DateTime? RevokedAt { get; private set; }
  16. /// <summary>회전 시 발급된 후속 토큰. race condition grace period 흡수용.</summary>
  17. public string? ReplacedByToken { get; private set; }
  18. private RefreshToken() { }
  19. public static RefreshToken Create(
  20. int memberID,
  21. string token,
  22. DateTime expiresAt
  23. ) {
  24. return new RefreshToken
  25. {
  26. MemberID = memberID,
  27. Token = token,
  28. ExpiresAt = expiresAt
  29. };
  30. }
  31. public void Revoke()
  32. {
  33. IsRevoked = true;
  34. RevokedAt = DateTime.UtcNow;
  35. }
  36. /// <summary>회전 시 호출 — 새 토큰을 ReplacedByToken에 기록.</summary>
  37. public void MarkReplaced(string newToken)
  38. {
  39. ReplacedByToken = newToken;
  40. }
  41. public bool IsExpired => DateTime.UtcNow >= ExpiresAt;
  42. public bool IsActive => !IsRevoked && !IsExpired;
  43. }