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('=');
}
}