chore: 提交现有修改
This commit is contained in:
@@ -10,18 +10,12 @@ namespace TakeoutSaaS.Infrastructure.Identity.Persistence;
|
||||
/// <summary>
|
||||
/// EF Core 后台用户仓储实现。
|
||||
/// </summary>
|
||||
public sealed class EfIdentityUserRepository : IIdentityUserRepository
|
||||
public sealed class EfIdentityUserRepository(IdentityDbContext dbContext) : IIdentityUserRepository
|
||||
{
|
||||
private readonly IdentityDbContext _dbContext;
|
||||
|
||||
public EfIdentityUserRepository(IdentityDbContext dbContext)
|
||||
{
|
||||
_dbContext = dbContext;
|
||||
}
|
||||
|
||||
public Task<IdentityUser?> FindByAccountAsync(string account, CancellationToken cancellationToken = default)
|
||||
=> _dbContext.IdentityUsers.AsNoTracking().FirstOrDefaultAsync(x => x.Account == account, cancellationToken);
|
||||
=> dbContext.IdentityUsers.AsNoTracking().FirstOrDefaultAsync(x => x.Account == account, cancellationToken);
|
||||
|
||||
public Task<IdentityUser?> FindByIdAsync(long userId, CancellationToken cancellationToken = default)
|
||||
=> _dbContext.IdentityUsers.AsNoTracking().FirstOrDefaultAsync(x => x.Id == userId, cancellationToken);
|
||||
=> dbContext.IdentityUsers.AsNoTracking().FirstOrDefaultAsync(x => x.Id == userId, cancellationToken);
|
||||
}
|
||||
|
||||
@@ -10,24 +10,18 @@ namespace TakeoutSaaS.Infrastructure.Identity.Persistence;
|
||||
/// <summary>
|
||||
/// EF Core 小程序用户仓储实现。
|
||||
/// </summary>
|
||||
public sealed class EfMiniUserRepository : IMiniUserRepository
|
||||
public sealed class EfMiniUserRepository(IdentityDbContext dbContext) : IMiniUserRepository
|
||||
{
|
||||
private readonly IdentityDbContext _dbContext;
|
||||
|
||||
public EfMiniUserRepository(IdentityDbContext dbContext)
|
||||
{
|
||||
_dbContext = dbContext;
|
||||
}
|
||||
|
||||
public Task<MiniUser?> FindByOpenIdAsync(string openId, CancellationToken cancellationToken = default)
|
||||
=> _dbContext.MiniUsers.AsNoTracking().FirstOrDefaultAsync(x => x.OpenId == openId, cancellationToken);
|
||||
=> dbContext.MiniUsers.AsNoTracking().FirstOrDefaultAsync(x => x.OpenId == openId, cancellationToken);
|
||||
|
||||
public Task<MiniUser?> FindByIdAsync(long id, CancellationToken cancellationToken = default)
|
||||
=> _dbContext.MiniUsers.AsNoTracking().FirstOrDefaultAsync(x => x.Id == id, cancellationToken);
|
||||
=> dbContext.MiniUsers.AsNoTracking().FirstOrDefaultAsync(x => x.Id == id, cancellationToken);
|
||||
|
||||
public async Task<MiniUser> CreateOrUpdateAsync(string openId, string? unionId, string? nickname, string? avatar, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var user = await _dbContext.MiniUsers.FirstOrDefaultAsync(x => x.OpenId == openId, cancellationToken);
|
||||
var user = await dbContext.MiniUsers.FirstOrDefaultAsync(x => x.OpenId == openId, cancellationToken);
|
||||
if (user == null)
|
||||
{
|
||||
user = new MiniUser
|
||||
@@ -39,7 +33,7 @@ public sealed class EfMiniUserRepository : IMiniUserRepository
|
||||
Avatar = avatar,
|
||||
TenantId = tenantId
|
||||
};
|
||||
_dbContext.MiniUsers.Add(user);
|
||||
dbContext.MiniUsers.Add(user);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -48,7 +42,7 @@ public sealed class EfMiniUserRepository : IMiniUserRepository
|
||||
user.Avatar = avatar ?? user.Avatar;
|
||||
}
|
||||
|
||||
await _dbContext.SaveChangesAsync(cancellationToken);
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,21 +13,14 @@ namespace TakeoutSaaS.Infrastructure.Identity.Services;
|
||||
/// <summary>
|
||||
/// Redis 登录限流实现。
|
||||
/// </summary>
|
||||
public sealed class RedisLoginRateLimiter : ILoginRateLimiter
|
||||
public sealed class RedisLoginRateLimiter(IDistributedCache cache, IOptions<LoginRateLimitOptions> options) : ILoginRateLimiter
|
||||
{
|
||||
private readonly IDistributedCache _cache;
|
||||
private readonly LoginRateLimitOptions _options;
|
||||
|
||||
public RedisLoginRateLimiter(IDistributedCache cache, IOptions<LoginRateLimitOptions> options)
|
||||
{
|
||||
_cache = cache;
|
||||
_options = options.Value;
|
||||
}
|
||||
private readonly LoginRateLimitOptions _options = options.Value;
|
||||
|
||||
public async Task EnsureAllowedAsync(string key, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var cacheKey = BuildKey(key);
|
||||
var current = await _cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
var current = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||
var count = string.IsNullOrWhiteSpace(current) ? 0 : int.Parse(current);
|
||||
if (count >= _options.MaxAttempts)
|
||||
{
|
||||
@@ -35,7 +28,7 @@ public sealed class RedisLoginRateLimiter : ILoginRateLimiter
|
||||
}
|
||||
|
||||
count++;
|
||||
await _cache.SetStringAsync(
|
||||
await cache.SetStringAsync(
|
||||
cacheKey,
|
||||
count.ToString(),
|
||||
new DistributedCacheEntryOptions
|
||||
@@ -46,7 +39,7 @@ public sealed class RedisLoginRateLimiter : ILoginRateLimiter
|
||||
}
|
||||
|
||||
public Task ResetAsync(string key, CancellationToken cancellationToken = default)
|
||||
=> _cache.RemoveAsync(BuildKey(key), cancellationToken);
|
||||
=> cache.RemoveAsync(BuildKey(key), cancellationToken);
|
||||
|
||||
private static string BuildKey(string key) => $"identity:login:{key}";
|
||||
}
|
||||
|
||||
@@ -14,17 +14,10 @@ namespace TakeoutSaaS.Infrastructure.Identity.Services;
|
||||
/// <summary>
|
||||
/// Redis 刷新令牌存储。
|
||||
/// </summary>
|
||||
public sealed class RedisRefreshTokenStore : IRefreshTokenStore
|
||||
public sealed class RedisRefreshTokenStore(IDistributedCache cache, IOptions<RefreshTokenStoreOptions> options) : IRefreshTokenStore
|
||||
{
|
||||
private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web);
|
||||
private readonly IDistributedCache _cache;
|
||||
private readonly RefreshTokenStoreOptions _options;
|
||||
|
||||
public RedisRefreshTokenStore(IDistributedCache cache, IOptions<RefreshTokenStoreOptions> options)
|
||||
{
|
||||
_cache = cache;
|
||||
_options = options.Value;
|
||||
}
|
||||
private readonly RefreshTokenStoreOptions _options = options.Value;
|
||||
|
||||
public async Task<RefreshTokenDescriptor> IssueAsync(long userId, DateTime expiresAt, CancellationToken cancellationToken = default)
|
||||
{
|
||||
@@ -33,14 +26,14 @@ public sealed class RedisRefreshTokenStore : IRefreshTokenStore
|
||||
|
||||
var key = BuildKey(token);
|
||||
var entryOptions = new DistributedCacheEntryOptions { AbsoluteExpiration = expiresAt };
|
||||
await _cache.SetStringAsync(key, JsonSerializer.Serialize(descriptor, JsonOptions), entryOptions, cancellationToken);
|
||||
await cache.SetStringAsync(key, JsonSerializer.Serialize(descriptor, JsonOptions), entryOptions, cancellationToken);
|
||||
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
public async Task<RefreshTokenDescriptor?> GetAsync(string refreshToken, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var json = await _cache.GetStringAsync(BuildKey(refreshToken), cancellationToken);
|
||||
var json = await cache.GetStringAsync(BuildKey(refreshToken), cancellationToken);
|
||||
return string.IsNullOrWhiteSpace(json)
|
||||
? null
|
||||
: JsonSerializer.Deserialize<RefreshTokenDescriptor>(json, JsonOptions);
|
||||
@@ -56,7 +49,7 @@ public sealed class RedisRefreshTokenStore : IRefreshTokenStore
|
||||
|
||||
var updated = descriptor with { Revoked = true };
|
||||
var entryOptions = new DistributedCacheEntryOptions { AbsoluteExpiration = updated.ExpiresAt };
|
||||
await _cache.SetStringAsync(BuildKey(refreshToken), JsonSerializer.Serialize(updated, JsonOptions), entryOptions, cancellationToken);
|
||||
await cache.SetStringAsync(BuildKey(refreshToken), JsonSerializer.Serialize(updated, JsonOptions), entryOptions, cancellationToken);
|
||||
}
|
||||
|
||||
private string BuildKey(string token) => $"{_options.Prefix}{token}";
|
||||
|
||||
@@ -15,21 +15,14 @@ namespace TakeoutSaaS.Infrastructure.Identity.Services;
|
||||
/// <summary>
|
||||
/// 微信 code2Session 实现
|
||||
/// </summary>
|
||||
public sealed class WeChatAuthService : IWeChatAuthService
|
||||
public sealed class WeChatAuthService(HttpClient httpClient, IOptions<WeChatMiniOptions> options) : IWeChatAuthService
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly WeChatMiniOptions _options;
|
||||
|
||||
public WeChatAuthService(HttpClient httpClient, IOptions<WeChatMiniOptions> options)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_options = options.Value;
|
||||
}
|
||||
private readonly WeChatMiniOptions _options = options.Value;
|
||||
|
||||
public async Task<WeChatSessionInfo> Code2SessionAsync(string code, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var requestUri = $"sns/jscode2session?appid={Uri.EscapeDataString(_options.AppId)}&secret={Uri.EscapeDataString(_options.Secret)}&js_code={Uri.EscapeDataString(code)}&grant_type=authorization_code";
|
||||
using var response = await _httpClient.GetAsync(requestUri, cancellationToken);
|
||||
using var response = await httpClient.GetAsync(requestUri, cancellationToken);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var payload = await response.Content.ReadFromJsonAsync<WeChatSessionResponse>(cancellationToken: cancellationToken);
|
||||
|
||||
Reference in New Issue
Block a user