2020-02-04 16:51:15 +08:00
|
|
|
using System;
|
2026-08-07 03:45:19 +08:00
|
|
|
using System.Collections.Concurrent;
|
2026-05-03 19:34:47 +08:00
|
|
|
using System.Collections.Generic;
|
2020-02-04 16:51:15 +08:00
|
|
|
using Microsoft.Extensions.Caching.Distributed;
|
2026-08-07 03:45:19 +08:00
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
2020-08-05 15:29:56 +08:00
|
|
|
using SimApi.Communications;
|
2026-05-03 19:34:47 +08:00
|
|
|
using StackExchange.Redis;
|
2020-02-04 16:51:15 +08:00
|
|
|
|
2024-03-23 07:29:43 +08:00
|
|
|
namespace SimApi.Helpers;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2026-08-07 03:45:19 +08:00
|
|
|
/// 认证助手(支持 Redis 和 InMemory 两种模式)
|
2024-03-23 07:29:43 +08:00
|
|
|
/// </summary>
|
2026-08-07 03:45:19 +08:00
|
|
|
public class SimApiAuth
|
2020-02-04 16:51:15 +08:00
|
|
|
{
|
2026-05-03 19:34:47 +08:00
|
|
|
private const string TokenCacheKey = "SimApi:Auth:Token:{token}";
|
|
|
|
|
private const string TokenSetCacheKey = "SimApi:Auth:User:{userId}";
|
2026-08-07 03:45:19 +08:00
|
|
|
|
|
|
|
|
private readonly IDistributedCache _cache;
|
|
|
|
|
private readonly IDatabase? _redisDb;
|
|
|
|
|
|
|
|
|
|
// InMemory 模式:用户 → Token集合
|
|
|
|
|
private readonly ConcurrentDictionary<string, ConcurrentDictionary<string, byte>> _userTokens = new();
|
|
|
|
|
|
|
|
|
|
public SimApiAuth(IDistributedCache cache, IServiceProvider sp)
|
|
|
|
|
{
|
|
|
|
|
_cache = cache;
|
|
|
|
|
_redisDb = sp.GetService<IConnectionMultiplexer>()?.GetDatabase();
|
|
|
|
|
}
|
2026-05-03 19:34:47 +08:00
|
|
|
|
2020-02-04 16:51:15 +08:00
|
|
|
/// <summary>
|
2024-08-19 03:39:35 +08:00
|
|
|
/// 登录信息
|
2020-02-04 16:51:15 +08:00
|
|
|
/// </summary>
|
2024-08-19 03:39:35 +08:00
|
|
|
/// <param name="loginItem"></param>
|
2026-05-03 19:34:47 +08:00
|
|
|
/// <param name="expireTime"></param>
|
2024-03-24 17:31:22 +08:00
|
|
|
/// <param name="token"></param>
|
2024-03-23 07:29:43 +08:00
|
|
|
/// <returns></returns>
|
2026-05-03 19:34:47 +08:00
|
|
|
public string Login(SimApiLoginItem loginItem, TimeSpan? expireTime = null, string? token = null)
|
2020-02-04 16:51:15 +08:00
|
|
|
{
|
2026-05-03 19:34:47 +08:00
|
|
|
expireTime ??= TimeSpan.FromDays(7);
|
2024-08-19 03:39:35 +08:00
|
|
|
token ??= Guid.NewGuid().ToString();
|
2026-05-03 19:34:47 +08:00
|
|
|
var cacheKey = TokenCacheKey.Replace("{token}", token);
|
|
|
|
|
var setCacheKey = TokenSetCacheKey.Replace("{userId}", loginItem.Id);
|
2026-08-07 03:45:19 +08:00
|
|
|
|
|
|
|
|
_cache.SetString(cacheKey, SimApiUtil.Json(loginItem),
|
|
|
|
|
new DistributedCacheEntryOptions { SlidingExpiration = expireTime });
|
|
|
|
|
|
|
|
|
|
if (_redisDb != null)
|
|
|
|
|
{
|
|
|
|
|
_redisDb.SetAdd(setCacheKey, token);
|
|
|
|
|
_redisDb.KeyExpire(setCacheKey, expireTime.Value);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
var tokens = _userTokens.GetOrAdd(loginItem.Id, _ => new ConcurrentDictionary<string, byte>());
|
|
|
|
|
tokens.TryAdd(token, 0);
|
|
|
|
|
}
|
2026-05-03 19:34:47 +08:00
|
|
|
|
2024-08-19 03:39:35 +08:00
|
|
|
return token;
|
2024-06-27 04:38:04 +08:00
|
|
|
}
|
|
|
|
|
|
2025-10-25 17:12:39 +08:00
|
|
|
/// <summary>
|
|
|
|
|
/// 更新登陆信息
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="loginItem"></param>
|
|
|
|
|
/// <param name="token"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public string Update(SimApiLoginItem loginItem, string token)
|
|
|
|
|
{
|
2026-05-03 19:34:47 +08:00
|
|
|
var cacheKey = TokenCacheKey.Replace("{token}", token);
|
2026-08-07 03:45:19 +08:00
|
|
|
_cache.SetString(cacheKey, SimApiUtil.Json(loginItem));
|
|
|
|
|
|
|
|
|
|
if (_redisDb != null)
|
|
|
|
|
{
|
|
|
|
|
var ttl = _redisDb.KeyTimeToLive(cacheKey);
|
|
|
|
|
var setCacheKey = TokenSetCacheKey.Replace("{userId}", loginItem.Id);
|
|
|
|
|
_redisDb.KeyExpire(setCacheKey, ttl);
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-25 17:12:39 +08:00
|
|
|
return token;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-03 19:34:47 +08:00
|
|
|
|
2024-03-24 17:31:22 +08:00
|
|
|
/// <summary>
|
|
|
|
|
/// 获取登陆信息
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="token"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public SimApiLoginItem? GetLogin(string token)
|
|
|
|
|
{
|
2026-05-03 19:34:47 +08:00
|
|
|
var cacheKey = TokenCacheKey.Replace("{token}", token);
|
2026-08-07 03:45:19 +08:00
|
|
|
var login = _cache.GetString(cacheKey);
|
2026-05-03 19:34:47 +08:00
|
|
|
var resp = login != null ? SimApiUtil.FromJson<SimApiLoginItem>(login) : null;
|
2026-08-07 03:45:19 +08:00
|
|
|
|
|
|
|
|
if (resp != null && _redisDb != null)
|
2026-05-03 19:34:47 +08:00
|
|
|
{
|
|
|
|
|
var ttl = _redisDb.KeyTimeToLive(cacheKey);
|
|
|
|
|
var setCacheKey = TokenSetCacheKey.Replace("{userId}", resp.Id);
|
|
|
|
|
_redisDb.KeyExpire(setCacheKey, ttl);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return resp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取所有的登录token
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="userId"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public SimApiLoginItem[] GetAllLogins(string userId)
|
|
|
|
|
{
|
2026-08-07 03:45:19 +08:00
|
|
|
if (_redisDb != null)
|
2026-05-03 19:34:47 +08:00
|
|
|
{
|
2026-08-07 03:45:19 +08:00
|
|
|
var setCacheKey = TokenSetCacheKey.Replace("{userId}", userId);
|
|
|
|
|
var allLogins = _redisDb.SetMembers(setCacheKey).ToStringArray();
|
|
|
|
|
var resp = new List<SimApiLoginItem>();
|
|
|
|
|
foreach (var login in allLogins)
|
2026-05-03 19:34:47 +08:00
|
|
|
{
|
2026-08-07 03:45:19 +08:00
|
|
|
if (login != null)
|
2026-05-03 19:34:47 +08:00
|
|
|
{
|
2026-08-07 03:45:19 +08:00
|
|
|
var item = GetLogin(login);
|
|
|
|
|
if (item != null)
|
|
|
|
|
resp.Add(item);
|
|
|
|
|
else
|
|
|
|
|
_redisDb.SetRemove(setCacheKey, login);
|
2026-05-03 19:34:47 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-07 03:45:19 +08:00
|
|
|
return resp.ToArray();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (!_userTokens.TryGetValue(userId, out var tokens))
|
|
|
|
|
return [];
|
|
|
|
|
|
|
|
|
|
var resp = new List<SimApiLoginItem>();
|
|
|
|
|
foreach (var token in tokens.Keys)
|
|
|
|
|
{
|
|
|
|
|
var item = GetLogin(token);
|
|
|
|
|
if (item != null)
|
|
|
|
|
resp.Add(item);
|
|
|
|
|
else
|
|
|
|
|
tokens.TryRemove(token, out _);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return resp.ToArray();
|
|
|
|
|
}
|
2026-05-03 19:34:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 退出所有登录
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="userId"></param>
|
|
|
|
|
public void LogoutAll(string userId)
|
|
|
|
|
{
|
2026-08-07 03:45:19 +08:00
|
|
|
if (_redisDb != null)
|
2026-05-03 19:34:47 +08:00
|
|
|
{
|
2026-08-07 03:45:19 +08:00
|
|
|
var setCacheKey = TokenSetCacheKey.Replace("{userId}", userId);
|
|
|
|
|
var allLogins = _redisDb.SetMembers(setCacheKey).ToStringArray();
|
|
|
|
|
foreach (var login in allLogins)
|
2026-05-03 19:34:47 +08:00
|
|
|
{
|
2026-08-07 03:45:19 +08:00
|
|
|
if (login != null)
|
|
|
|
|
{
|
|
|
|
|
var cacheKey = TokenCacheKey.Replace("{token}", login);
|
|
|
|
|
_cache.Remove(cacheKey);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_redisDb.KeyDelete(setCacheKey);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (_userTokens.TryRemove(userId, out var tokens))
|
|
|
|
|
{
|
|
|
|
|
foreach (var token in tokens.Keys)
|
|
|
|
|
{
|
|
|
|
|
var cacheKey = TokenCacheKey.Replace("{token}", token);
|
|
|
|
|
_cache.Remove(cacheKey);
|
|
|
|
|
}
|
2026-05-03 19:34:47 +08:00
|
|
|
}
|
|
|
|
|
}
|
2024-03-24 17:31:22 +08:00
|
|
|
}
|
|
|
|
|
|
2024-03-23 07:29:43 +08:00
|
|
|
/// <summary>
|
|
|
|
|
/// 退出登陆
|
|
|
|
|
/// </summary>
|
2026-05-03 19:34:47 +08:00
|
|
|
/// <param name="token">登陆标识</param>
|
|
|
|
|
public void Logout(string token)
|
2024-03-23 07:29:43 +08:00
|
|
|
{
|
2026-05-03 19:34:47 +08:00
|
|
|
var item = GetLogin(token);
|
2026-08-07 03:45:19 +08:00
|
|
|
|
|
|
|
|
if (_redisDb != null)
|
2020-02-18 08:07:51 +08:00
|
|
|
{
|
2026-08-07 03:45:19 +08:00
|
|
|
if (item != null)
|
|
|
|
|
{
|
|
|
|
|
var setCacheKey = TokenSetCacheKey.Replace("{userId}", item.Id);
|
|
|
|
|
_redisDb.SetRemove(setCacheKey, token);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (item != null && _userTokens.TryGetValue(item.Id, out var tokens))
|
|
|
|
|
tokens.TryRemove(token, out _);
|
2020-06-28 06:28:51 +08:00
|
|
|
}
|
2026-05-04 15:35:47 +08:00
|
|
|
|
|
|
|
|
var cacheKey = TokenCacheKey.Replace("{token}", token);
|
2026-08-07 03:45:19 +08:00
|
|
|
_cache.Remove(cacheKey);
|
2020-02-04 16:51:15 +08:00
|
|
|
}
|
2026-08-07 03:45:19 +08:00
|
|
|
}
|