EmailVerifyTokenRepository.cs 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. using Microsoft.EntityFrameworkCore;
  2. using System.Security.Cryptography;
  3. using System.Text.Json;
  4. using bitforum.Constants;
  5. using bitforum.Models.Account;
  6. namespace bitforum.Repository
  7. {
  8. public interface IEmailVerifyTokenRepository
  9. {
  10. /// <summary>
  11. /// 새 토큰 생성 및 저장
  12. /// </summary>
  13. public Task<string> GenerateTokenAsync(string email, VerificationType type, AdditionalData? additional = null);
  14. /// <summary>
  15. /// 토큰 검증 및 사용 처리
  16. /// </summary>
  17. public Task<EmailVerifyToken?> ValidateTokenAsync(string token, VerificationType type);
  18. /// <summary>
  19. /// 만료된 토큰 삭제
  20. /// </summary>
  21. public Task CleanupExpiredTokensAsync();
  22. }
  23. public class EmailVerifyTokenRepository : IEmailVerifyTokenRepository
  24. {
  25. private readonly DefaultDbContext _db;
  26. private readonly int _tokenExpirationMinutes = 60;
  27. public EmailVerifyTokenRepository(DefaultDbContext db)
  28. {
  29. _db = db;
  30. }
  31. public async Task<string> GenerateTokenAsync(string email, VerificationType type, AdditionalData? additional = null)
  32. {
  33. _db.EmailVerifyToken.RemoveRange(
  34. _db.EmailVerifyToken.Where(x => x.Email == email && x.Type == type)
  35. );
  36. var token = Convert.ToBase64String(RandomNumberGenerator.GetBytes(64));
  37. var expiration = DateTime.UtcNow.AddMinutes(_tokenExpirationMinutes);
  38. _db.EmailVerifyToken.Add(new EmailVerifyToken
  39. {
  40. Email = email,
  41. Token = token,
  42. Expiration = expiration,
  43. Type = type,
  44. Additional = additional == null ? null : JsonSerializer.Serialize(additional)
  45. });
  46. await _db.SaveChangesAsync();
  47. return token;
  48. }
  49. public async Task<EmailVerifyToken?> ValidateTokenAsync(string token, VerificationType type)
  50. {
  51. var data = await _db.EmailVerifyToken.FirstOrDefaultAsync(x => x.Token == token && x.Type == type && !x.IsVerified && x.Expiration > DateTime.UtcNow);
  52. if (data == null)
  53. {
  54. return null;
  55. }
  56. data.IsVerified = true;
  57. await _db.SaveChangesAsync();
  58. return data;
  59. }
  60. public async Task CleanupExpiredTokensAsync()
  61. {
  62. _db.EmailVerifyToken.RemoveRange(
  63. _db.EmailVerifyToken.Where(x => x.Expiration < DateTime.UtcNow)
  64. );
  65. await _db.SaveChangesAsync();
  66. }
  67. }
  68. }