NiceAuthSession.cs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. using System.ComponentModel.DataAnnotations;
  2. using System.ComponentModel.DataAnnotations.Schema;
  3. using Domain.Entities.Developers.ValueObject;
  4. namespace Domain.Entities.Developers;
  5. /// <summary>
  6. /// NICE 통합인증 1회 진행 세션. StartKyc 시 생성 → callback 에서 매칭 → Completed/Failed/Expired.
  7. ///
  8. /// 가이드: .claude/plan/nice-auth-integration.md §5
  9. /// </summary>
  10. public class NiceAuthSession
  11. {
  12. /// <summary>유효기간: 10분 (NICE transaction_id 의 효력과 동일).</summary>
  13. public static readonly TimeSpan DefaultLifetime = TimeSpan.FromMinutes(10);
  14. [ForeignKey(nameof(DeveloperID))]
  15. public virtual Developer? Developer { get; private set; }
  16. [Key]
  17. public int ID { get; private set; }
  18. public int DeveloperID { get; private set; }
  19. /// <summary>
  20. /// 가맹점 측 세션 식별자. NICE return_url path segment 로 embed → callback 매칭.
  21. /// URL-safe (Base64Url no-padding 22 char).
  22. /// </summary>
  23. public string SessionToken { get; private set; } = default!;
  24. /// <summary>NICE auth/url request 의 request_no.</summary>
  25. public string RequestNo { get; private set; } = default!;
  26. /// <summary>NICE auth/url 응답의 transaction_id.</summary>
  27. public string TransactionID { get; private set; } = default!;
  28. /// <summary>NICE 표준창이 return_url 로 넘긴 web_transaction_id (callback 시점에 set).</summary>
  29. public string? WebTransactionID { get; private set; }
  30. /// <summary>auth/url 호출 시점 token 의 ticket. result 복호화 KDF 입력.</summary>
  31. public string Ticket { get; private set; } = default!;
  32. /// <summary>auth/url 호출 시점 token 의 iterators. result 복호화 KDF 입력.</summary>
  33. public int Iterators { get; private set; }
  34. public NiceAuthSessionStatus Status { get; private set; } = NiceAuthSessionStatus.Pending;
  35. public string? FailReason { get; private set; }
  36. public DateTime CreatedAt { get; private set; } = DateTime.UtcNow;
  37. public DateTime ExpiresAt { get; private set; }
  38. public DateTime? CompletedAt { get; private set; }
  39. private NiceAuthSession() { }
  40. public static NiceAuthSession Create(
  41. int developerID,
  42. string sessionToken,
  43. string requestNo,
  44. string transactionID,
  45. string ticket,
  46. int iterators
  47. ) {
  48. if (string.IsNullOrWhiteSpace(sessionToken))
  49. {
  50. throw new ArgumentException("Session token is required.", nameof(sessionToken));
  51. }
  52. if (string.IsNullOrWhiteSpace(requestNo))
  53. {
  54. throw new ArgumentException("Request no is required.", nameof(requestNo));
  55. }
  56. if (string.IsNullOrWhiteSpace(transactionID))
  57. {
  58. throw new ArgumentException("Transaction ID is required.", nameof(transactionID));
  59. }
  60. if (string.IsNullOrWhiteSpace(ticket))
  61. {
  62. throw new ArgumentException("Ticket is required.", nameof(ticket));
  63. }
  64. if (iterators <= 0)
  65. {
  66. throw new ArgumentOutOfRangeException(nameof(iterators), iterators, "iterators must be positive.");
  67. }
  68. var now = DateTime.UtcNow;
  69. return new NiceAuthSession
  70. {
  71. DeveloperID = developerID,
  72. SessionToken = sessionToken,
  73. RequestNo = requestNo,
  74. TransactionID = transactionID,
  75. Ticket = ticket,
  76. Iterators = iterators,
  77. Status = NiceAuthSessionStatus.Pending,
  78. CreatedAt = now,
  79. ExpiresAt = now + DefaultLifetime
  80. };
  81. }
  82. /// <summary>callback 에서 web_transaction_id 받아 기록 — result 호출 직전 단계.</summary>
  83. public void MarkWebTransactionReceived(string webTransactionID)
  84. {
  85. if (string.IsNullOrWhiteSpace(webTransactionID))
  86. {
  87. throw new ArgumentException("Web transaction ID is required.", nameof(webTransactionID));
  88. }
  89. WebTransactionID = webTransactionID;
  90. }
  91. public void MarkCompleted()
  92. {
  93. Status = NiceAuthSessionStatus.Completed;
  94. CompletedAt = DateTime.UtcNow;
  95. }
  96. public void MarkFailed(string reason)
  97. {
  98. Status = NiceAuthSessionStatus.Failed;
  99. FailReason = reason;
  100. CompletedAt = DateTime.UtcNow;
  101. }
  102. public void MarkExpired()
  103. {
  104. Status = NiceAuthSessionStatus.Expired;
  105. FailReason = "유효시간이 만료되었습니다.";
  106. CompletedAt = DateTime.UtcNow;
  107. }
  108. public bool IsExpired(DateTime utcNow) => utcNow >= ExpiresAt;
  109. public bool CanProcessCallback() => Status == NiceAuthSessionStatus.Pending;
  110. }