using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Options; using System.Security.Cryptography; using TakeoutSaaS.Application.Identity.Abstractions; using TakeoutSaaS.Infrastructure.Identity.Options; namespace TakeoutSaaS.Infrastructure.Identity.Services; /// /// Redis 管理后台重置密码链接令牌存储。 /// public sealed class RedisAdminPasswordResetTokenStore( IDistributedCache cache, IOptions options) : IAdminPasswordResetTokenStore { private readonly AdminPasswordResetOptions _options = options.Value; /// public async Task IssueAsync(long userId, DateTime expiresAt, CancellationToken cancellationToken = default) { // 1. 生成 URL 安全的随机令牌 var token = GenerateUrlSafeToken(48); // 2. 写入缓存(Value:userId) await cache.SetStringAsync(BuildKey(token), userId.ToString(), new DistributedCacheEntryOptions { AbsoluteExpiration = expiresAt }, cancellationToken); // 3. 返回令牌 return token; } /// public async Task ConsumeAsync(string token, CancellationToken cancellationToken = default) { // 1. 读取缓存 var key = BuildKey(token); var value = await cache.GetStringAsync(key, cancellationToken); if (string.IsNullOrWhiteSpace(value)) { return null; } // 2. 删除缓存(一次性令牌) await cache.RemoveAsync(key, cancellationToken); // 3. 解析用户 ID return long.TryParse(value, out var userId) ? userId : null; } private string BuildKey(string token) => $"{_options.Prefix}{token}"; private static string GenerateUrlSafeToken(int bytesLength) { var bytes = RandomNumberGenerator.GetBytes(bytesLength); var token = Convert.ToBase64String(bytes); return token .Replace('+', '-') .Replace('/', '_') .TrimEnd('='); } }