Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e17b9d9eed | ||
|
|
80a05ea20b | ||
|
|
33f7cff11c | ||
|
|
c7a4395000 | ||
|
|
bf98792f96 |
@@ -437,3 +437,4 @@ MigrationBackup/
|
|||||||
|
|
||||||
# BitFun snapshot data - auto managed
|
# BitFun snapshot data - auto managed
|
||||||
.bitfun/
|
.bitfun/
|
||||||
|
/.bitfun/search/flashgrep-index/
|
||||||
|
|||||||
@@ -1,11 +1,25 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace SimApi.Configurations;
|
namespace SimApi.Configurations;
|
||||||
|
|
||||||
public class SimApiOptions
|
public class SimApiOptions
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Redis配置
|
||||||
|
/// </summary>
|
||||||
public string? RedisConfiguration { get; set; }
|
public string? RedisConfiguration { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 原样返回给前端的配置信息
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<string, object>? WebConfig { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// WebConfig返回是否包含版本信息
|
||||||
|
/// </summary>
|
||||||
|
public bool WebConfigIncludeVersion { get; set; } = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否启用后台任务系统 *基于Hangfire
|
/// 是否启用后台任务系统 *基于Hangfire
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -17,6 +31,12 @@ public class SimApiOptions
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool EnableSimApiAuth { get; set; }
|
public bool EnableSimApiAuth { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启用Cache功能
|
||||||
|
/// </summary>
|
||||||
|
public bool EnableSimApiCache { get; set; } = true;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 启用SimApi网关授权, 基于上层网关透传的身份令牌验证
|
/// 启用SimApi网关授权, 基于上层网关透传的身份令牌验证
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -11,4 +11,9 @@ public class SimApiRequestLogOptions
|
|||||||
/// 是否打印完整的响应体
|
/// 是否打印完整的响应体
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool ShowFullResponse { get; set; }
|
public bool ShowFullResponse { get; set; }
|
||||||
}
|
|
||||||
|
/// <summary>
|
||||||
|
/// 请求字段显示最长长度
|
||||||
|
/// </summary>
|
||||||
|
public int RequestStringLogLength { get; set; } = 0;
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
public class SimApiRouteOptions
|
public class SimApiRouteOptions
|
||||||
{
|
{
|
||||||
public string? VersionRoute = "/versions";
|
|
||||||
public string? LogoutRoute = "/auth/logout";
|
public string? LogoutRoute = "/auth/logout";
|
||||||
public string? UserInfoRoute = "/user/info";
|
public string? UserInfoRoute = "/user/info";
|
||||||
|
public string? WebConfigRoute = "/config";
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,16 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
using SimApi.Attributes;
|
using SimApi.Attributes;
|
||||||
using SimApi.Communications;
|
using SimApi.Communications;
|
||||||
|
using SimApi.Configurations;
|
||||||
using SimApi.Helpers;
|
using SimApi.Helpers;
|
||||||
using static SimApi.Helpers.SimApiError;
|
using static SimApi.Helpers.SimApiError;
|
||||||
|
|
||||||
namespace SimApi.Controllers;
|
namespace SimApi.Controllers;
|
||||||
|
|
||||||
public class SimApiCommonController : SimApiBaseController
|
public class SimApiCommonController(SimApiOptions simApiOptions) : SimApiBaseController
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 错误回馈页面
|
/// 错误回馈页面
|
||||||
@@ -21,18 +24,27 @@ public class SimApiCommonController : SimApiBaseController
|
|||||||
Error(code);
|
Error(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 给前端的自定义信息
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
[HttpPost, HttpGet]
|
[HttpPost, HttpGet]
|
||||||
public Dictionary<string, string> Versions()
|
public Dictionary<string, object> WebConfig()
|
||||||
{
|
{
|
||||||
return new Dictionary<string, string>
|
var resp = simApiOptions.WebConfig!.ToDictionary();
|
||||||
|
if (simApiOptions.WebConfigIncludeVersion)
|
||||||
{
|
{
|
||||||
{ "SimApi", SimApiUtil.SimApiVersion },
|
resp.Add("Versions", new Dictionary<string, string>
|
||||||
{ "App", SimApiUtil.AppVersion }
|
{
|
||||||
};
|
{ "SimApi", SimApiUtil.SimApiVersion },
|
||||||
|
{ "App", SimApiUtil.AppVersion }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取已登录用户信息
|
/// 获取已登录用户信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
+108
-43
@@ -1,19 +1,32 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.Extensions.Caching.Distributed;
|
using Microsoft.Extensions.Caching.Distributed;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using SimApi.Communications;
|
using SimApi.Communications;
|
||||||
using StackExchange.Redis;
|
using StackExchange.Redis;
|
||||||
|
|
||||||
namespace SimApi.Helpers;
|
namespace SimApi.Helpers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 认证助手
|
/// 认证助手(支持 Redis 和 InMemory 两种模式)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SimApiAuth(IDistributedCache cache, IConnectionMultiplexer redis)
|
public class SimApiAuth
|
||||||
{
|
{
|
||||||
private const string TokenCacheKey = "SimApi:Auth:Token:{token}";
|
private const string TokenCacheKey = "SimApi:Auth:Token:{token}";
|
||||||
private const string TokenSetCacheKey = "SimApi:Auth:User:{userId}";
|
private const string TokenSetCacheKey = "SimApi:Auth:User:{userId}";
|
||||||
private readonly IDatabase _redisDb = redis.GetDatabase();
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 登录信息
|
/// 登录信息
|
||||||
@@ -28,13 +41,20 @@ public class SimApiAuth(IDistributedCache cache, IConnectionMultiplexer redis)
|
|||||||
token ??= Guid.NewGuid().ToString();
|
token ??= Guid.NewGuid().ToString();
|
||||||
var cacheKey = TokenCacheKey.Replace("{token}", token);
|
var cacheKey = TokenCacheKey.Replace("{token}", token);
|
||||||
var setCacheKey = TokenSetCacheKey.Replace("{userId}", loginItem.Id);
|
var setCacheKey = TokenSetCacheKey.Replace("{userId}", loginItem.Id);
|
||||||
_redisDb.SetAdd(setCacheKey, token);
|
|
||||||
cache.SetString(cacheKey, SimApiUtil.Json(loginItem),
|
_cache.SetString(cacheKey, SimApiUtil.Json(loginItem),
|
||||||
new DistributedCacheEntryOptions
|
new DistributedCacheEntryOptions { SlidingExpiration = expireTime });
|
||||||
{
|
|
||||||
SlidingExpiration = expireTime
|
if (_redisDb != null)
|
||||||
});
|
{
|
||||||
_redisDb.KeyExpire(setCacheKey, expireTime.Value);
|
_redisDb.SetAdd(setCacheKey, token);
|
||||||
|
_redisDb.KeyExpire(setCacheKey, expireTime.Value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var tokens = _userTokens.GetOrAdd(loginItem.Id, _ => new ConcurrentDictionary<string, byte>());
|
||||||
|
tokens.TryAdd(token, 0);
|
||||||
|
}
|
||||||
|
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
@@ -48,10 +68,15 @@ public class SimApiAuth(IDistributedCache cache, IConnectionMultiplexer redis)
|
|||||||
public string Update(SimApiLoginItem loginItem, string token)
|
public string Update(SimApiLoginItem loginItem, string token)
|
||||||
{
|
{
|
||||||
var cacheKey = TokenCacheKey.Replace("{token}", token);
|
var cacheKey = TokenCacheKey.Replace("{token}", token);
|
||||||
cache.SetString(cacheKey, SimApiUtil.Json(loginItem));
|
_cache.SetString(cacheKey, SimApiUtil.Json(loginItem));
|
||||||
var ttl = _redisDb.KeyTimeToLive(cacheKey);
|
|
||||||
var setCacheKey = TokenSetCacheKey.Replace("{userId}", loginItem.Id);
|
if (_redisDb != null)
|
||||||
_redisDb.KeyExpire(setCacheKey, ttl);
|
{
|
||||||
|
var ttl = _redisDb.KeyTimeToLive(cacheKey);
|
||||||
|
var setCacheKey = TokenSetCacheKey.Replace("{userId}", loginItem.Id);
|
||||||
|
_redisDb.KeyExpire(setCacheKey, ttl);
|
||||||
|
}
|
||||||
|
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,9 +89,10 @@ public class SimApiAuth(IDistributedCache cache, IConnectionMultiplexer redis)
|
|||||||
public SimApiLoginItem? GetLogin(string token)
|
public SimApiLoginItem? GetLogin(string token)
|
||||||
{
|
{
|
||||||
var cacheKey = TokenCacheKey.Replace("{token}", token);
|
var cacheKey = TokenCacheKey.Replace("{token}", token);
|
||||||
var login = cache.GetString(cacheKey);
|
var login = _cache.GetString(cacheKey);
|
||||||
var resp = login != null ? SimApiUtil.FromJson<SimApiLoginItem>(login) : null;
|
var resp = login != null ? SimApiUtil.FromJson<SimApiLoginItem>(login) : null;
|
||||||
if (resp != null)
|
|
||||||
|
if (resp != null && _redisDb != null)
|
||||||
{
|
{
|
||||||
var ttl = _redisDb.KeyTimeToLive(cacheKey);
|
var ttl = _redisDb.KeyTimeToLive(cacheKey);
|
||||||
var setCacheKey = TokenSetCacheKey.Replace("{userId}", resp.Id);
|
var setCacheKey = TokenSetCacheKey.Replace("{userId}", resp.Id);
|
||||||
@@ -83,26 +109,42 @@ public class SimApiAuth(IDistributedCache cache, IConnectionMultiplexer redis)
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public SimApiLoginItem[] GetAllLogins(string userId)
|
public SimApiLoginItem[] GetAllLogins(string userId)
|
||||||
{
|
{
|
||||||
var setCacheKey = TokenSetCacheKey.Replace("{userId}", userId);
|
if (_redisDb != null)
|
||||||
var allLogins = _redisDb.SetMembers(setCacheKey).ToStringArray();
|
|
||||||
var resp = new List<SimApiLoginItem>();
|
|
||||||
foreach (var login in allLogins)
|
|
||||||
{
|
{
|
||||||
if (login != null)
|
var setCacheKey = TokenSetCacheKey.Replace("{userId}", userId);
|
||||||
|
var allLogins = _redisDb.SetMembers(setCacheKey).ToStringArray();
|
||||||
|
var resp = new List<SimApiLoginItem>();
|
||||||
|
foreach (var login in allLogins)
|
||||||
{
|
{
|
||||||
var item = GetLogin(login);
|
if (login != null)
|
||||||
if (item != null)
|
|
||||||
{
|
{
|
||||||
resp.Add(item);
|
var item = GetLogin(login);
|
||||||
}
|
if (item != null)
|
||||||
else
|
resp.Add(item);
|
||||||
{
|
else
|
||||||
_redisDb.SetRemove(setCacheKey, login);
|
_redisDb.SetRemove(setCacheKey, login);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return resp.ToArray();
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -111,18 +153,32 @@ public class SimApiAuth(IDistributedCache cache, IConnectionMultiplexer redis)
|
|||||||
/// <param name="userId"></param>
|
/// <param name="userId"></param>
|
||||||
public void LogoutAll(string userId)
|
public void LogoutAll(string userId)
|
||||||
{
|
{
|
||||||
var setCacheKey = TokenSetCacheKey.Replace("{userId}", userId);
|
if (_redisDb != null)
|
||||||
var allLogins = _redisDb.SetMembers(setCacheKey).ToStringArray();
|
|
||||||
foreach (var login in allLogins)
|
|
||||||
{
|
{
|
||||||
if (login != null)
|
var setCacheKey = TokenSetCacheKey.Replace("{userId}", userId);
|
||||||
|
var allLogins = _redisDb.SetMembers(setCacheKey).ToStringArray();
|
||||||
|
foreach (var login in allLogins)
|
||||||
{
|
{
|
||||||
var cacheKey = TokenCacheKey.Replace("{token}", login);
|
if (login != null)
|
||||||
cache.Remove(cacheKey);
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_redisDb.KeyDelete(setCacheKey);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -132,13 +188,22 @@ public class SimApiAuth(IDistributedCache cache, IConnectionMultiplexer redis)
|
|||||||
public void Logout(string token)
|
public void Logout(string token)
|
||||||
{
|
{
|
||||||
var item = GetLogin(token);
|
var item = GetLogin(token);
|
||||||
if (item != null)
|
|
||||||
|
if (_redisDb != null)
|
||||||
{
|
{
|
||||||
var setCacheKey = TokenSetCacheKey.Replace("{userId}", item.Id);
|
if (item != null)
|
||||||
_redisDb.SetRemove(setCacheKey, token);
|
{
|
||||||
|
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 _);
|
||||||
}
|
}
|
||||||
|
|
||||||
var cacheKey = TokenCacheKey.Replace("{token}", token);
|
var cacheKey = TokenCacheKey.Replace("{token}", token);
|
||||||
cache.Remove(cacheKey);
|
_cache.Remove(cacheKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ using System.Threading.Tasks;
|
|||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using SimApi.Configurations;
|
using SimApi.Configurations;
|
||||||
|
using SimApi.Helpers;
|
||||||
|
|
||||||
namespace SimApi.Middlewares;
|
namespace SimApi.Middlewares;
|
||||||
|
|
||||||
@@ -53,7 +54,25 @@ public class SimApiRequestLogMiddleware(
|
|||||||
var requestBodyText = await new StreamReader(context.Request.Body).ReadToEndAsync();
|
var requestBodyText = await new StreamReader(context.Request.Body).ReadToEndAsync();
|
||||||
context.Request.Body.Seek(0, SeekOrigin.Begin);
|
context.Request.Body.Seek(0, SeekOrigin.Begin);
|
||||||
logMessage.AppendLine("*( RequestBody ) =>");
|
logMessage.AppendLine("*( RequestBody ) =>");
|
||||||
logMessage.AppendLine(requestBodyText);
|
if (options.RequestStringLogLength == 0)
|
||||||
|
{
|
||||||
|
logMessage.AppendLine(requestBodyText);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var reqLogs = SimApiUtil.FromJson<Dictionary<string, object>>(requestBodyText);
|
||||||
|
foreach (var reqLog in reqLogs)
|
||||||
|
{
|
||||||
|
if (reqLog.Value is not JsonElement { ValueKind: JsonValueKind.String } je) continue;
|
||||||
|
var str = je.GetString();
|
||||||
|
if (str?.Length > options.RequestStringLogLength)
|
||||||
|
{
|
||||||
|
reqLogs[reqLog.Key] = str[..options.RequestStringLogLength] + $"...({str.Length})";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logMessage.AppendLine(SimApiUtil.Json(reqLogs));
|
||||||
|
}
|
||||||
|
|
||||||
var originalBodyStream = context.Response.Body;
|
var originalBodyStream = context.Response.Body;
|
||||||
using var responseBody = new MemoryStream();
|
using var responseBody = new MemoryStream();
|
||||||
@@ -102,4 +121,4 @@ public class SimApiRequestLogMiddleware(
|
|||||||
|
|
||||||
edi?.Throw();
|
edi?.Throw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,6 +13,7 @@ ASP.NET Core API 基础框架库,提供统一异常拦截、响应封装、Tok
|
|||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
builder.Services.AddSimApi(options =>
|
builder.Services.AddSimApi(options =>
|
||||||
{
|
{
|
||||||
|
// RedisConfiguration 可选:配置则使用 Redis,不配则自动使用 InMemory
|
||||||
options.RedisConfiguration = "localhost:6379";
|
options.RedisConfiguration = "localhost:6379";
|
||||||
options.EnableSimApiAuth = true;
|
options.EnableSimApiAuth = true;
|
||||||
options.EnableSimApiDoc = true;
|
options.EnableSimApiDoc = true;
|
||||||
@@ -191,6 +192,26 @@ public class SimApiLoginItem {
|
|||||||
|
|
||||||
**Token 传参**: Header `Token: <value>`
|
**Token 传参**: Header `Token: <value>`
|
||||||
|
|
||||||
|
### 存储模式
|
||||||
|
|
||||||
|
`SimApiAuth` 内部自动判断,无需手动配置:
|
||||||
|
|
||||||
|
| 条件 | 存储后端 | 用户↔Token 映射 |
|
||||||
|
|------|---------|-----------------|
|
||||||
|
| 配置了 `RedisConfiguration` | Redis(`IDistributedCache` + Set) | Redis Set |
|
||||||
|
| 未配置 `RedisConfiguration` | InMemory(`DistributedMemoryCache`) | `ConcurrentDictionary` |
|
||||||
|
|
||||||
|
- **Redis 模式**:支持多实例共享,Token 持久化,适合生产环境
|
||||||
|
- **InMemory 模式**:零配置即可启用 `EnableSimApiAuth`,适合开发/测试/单实例场景。注意重启后所有登录态丢失
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// 不配 Redis 也能用 Auth
|
||||||
|
builder.Services.AddSimApi(options =>
|
||||||
|
{
|
||||||
|
options.EnableSimApiAuth = true; // 自动使用 InMemory
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
### 认证后处理 Hook — ISimApiAuthChecker
|
### 认证后处理 Hook — ISimApiAuthChecker
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
@@ -406,9 +427,11 @@ IMinioClient Client { get; } // 底层 MinIO 客户端
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 8. Redis 缓存 — SimApiCache
|
## 8. 缓存 — SimApiCache
|
||||||
|
|
||||||
依赖 `RedisConfiguration`,Key 自动加前缀 `SimApi:Cache:`。
|
通过 `EnableSimApiCache`(默认 `true`)控制。Key 自动加前缀 `SimApi:Cache:`。
|
||||||
|
|
||||||
|
存储后端与 `SimApiAuth` 一致:配了 `RedisConfiguration` 就用 Redis,否则用 InMemory。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
void Set(string key, object value, DistributedCacheEntryOptions? options = null);
|
void Set(string key, object value, DistributedCacheEntryOptions? options = null);
|
||||||
@@ -617,6 +640,7 @@ builder.Services.AddSimApi(options =>
|
|||||||
|
|
||||||
// 功能开关
|
// 功能开关
|
||||||
options.EnableSimApiAuth = false; // Token 认证
|
options.EnableSimApiAuth = false; // Token 认证
|
||||||
|
options.EnableSimApiCache = true; // 缓存(Redis 或 InMemory)
|
||||||
options.EnableSimApiAuthGate = false; // Auth Center 网关鉴权
|
options.EnableSimApiAuthGate = false; // Auth Center 网关鉴权
|
||||||
options.EnableSimApiDoc = false; // Swagger 文档
|
options.EnableSimApiDoc = false; // Swagger 文档
|
||||||
options.EnableSimApiStorage = false; // S3 存储
|
options.EnableSimApiStorage = false; // S3 存储
|
||||||
|
|||||||
+28
-13
@@ -36,11 +36,22 @@ public static class SimApiExtensions
|
|||||||
{
|
{
|
||||||
var simApiOptions = new SimApiOptions();
|
var simApiOptions = new SimApiOptions();
|
||||||
options?.Invoke(simApiOptions);
|
options?.Invoke(simApiOptions);
|
||||||
|
simApiOptions.WebConfig ??= new();
|
||||||
|
builder.AddSingleton(simApiOptions);
|
||||||
|
|
||||||
if (simApiOptions.RedisConfiguration != null)
|
if (simApiOptions.RedisConfiguration != null)
|
||||||
{
|
{
|
||||||
builder.AddStackExchangeRedisCache(x => x.Configuration = simApiOptions.RedisConfiguration);
|
builder.AddStackExchangeRedisCache(x => x.Configuration = simApiOptions.RedisConfiguration);
|
||||||
builder.AddSingleton<IConnectionMultiplexer>(_ =>
|
builder.AddSingleton<IConnectionMultiplexer>(_ =>
|
||||||
ConnectionMultiplexer.Connect(simApiOptions.RedisConfiguration));
|
ConnectionMultiplexer.Connect(simApiOptions.RedisConfiguration));
|
||||||
|
}
|
||||||
|
else if (simApiOptions.EnableSimApiAuth || simApiOptions.EnableSimApiCache)
|
||||||
|
{
|
||||||
|
builder.AddDistributedMemoryCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (simApiOptions.EnableSimApiCache)
|
||||||
|
{
|
||||||
builder.AddSingleton<SimApiCache>();
|
builder.AddSingleton<SimApiCache>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,6 +220,7 @@ public static class SimApiExtensions
|
|||||||
x.OperationFilter<SimApiSignOperationFilter>();
|
x.OperationFilter<SimApiSignOperationFilter>();
|
||||||
x.OperationFilter<AesBodyOperationFilter>();
|
x.OperationFilter<AesBodyOperationFilter>();
|
||||||
x.SchemaFilter<GlobalDynamicObjectSchemaFilter>();
|
x.SchemaFilter<GlobalDynamicObjectSchemaFilter>();
|
||||||
|
x.SchemaFilter<DictionarySchemaFilter>();
|
||||||
x.DocumentFilter<RemoveEmptyTagsFilter>();
|
x.DocumentFilter<RemoveEmptyTagsFilter>();
|
||||||
if (simApiOptions.EnableSimApiAuth)
|
if (simApiOptions.EnableSimApiAuth)
|
||||||
{
|
{
|
||||||
@@ -340,7 +352,6 @@ public static class SimApiExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
builder.AddSingleton(simApiOptions.SimApiRequestLogOptions);
|
builder.AddSingleton(simApiOptions.SimApiRequestLogOptions);
|
||||||
builder.AddSingleton(simApiOptions);
|
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,6 +370,11 @@ public static class SimApiExtensions
|
|||||||
logger.LogInformation("开始配置 RedisCache ...");
|
logger.LogInformation("开始配置 RedisCache ...");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.EnableSimApiCache)
|
||||||
|
{
|
||||||
|
logger.LogInformation("开始配置SimApiCache...");
|
||||||
|
}
|
||||||
|
|
||||||
//请求一下检测存储错误
|
//请求一下检测存储错误
|
||||||
if (options.EnableSimApiStorage)
|
if (options.EnableSimApiStorage)
|
||||||
{
|
{
|
||||||
@@ -446,18 +462,6 @@ public static class SimApiExtensions
|
|||||||
builder.UseMiddleware<SimApiAuthMiddleware>();
|
builder.UseMiddleware<SimApiAuthMiddleware>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (options.SimApiRouteOptions.VersionRoute != null)
|
|
||||||
{
|
|
||||||
logger.LogInformation("注册内置Route: Versions => {}", options.SimApiRouteOptions.LogoutRoute);
|
|
||||||
builder.MapControllerRoute(name: "Versions", pattern: options.SimApiRouteOptions.VersionRoute,
|
|
||||||
defaults: new
|
|
||||||
{
|
|
||||||
controller = "SimApiCommon",
|
|
||||||
action = "Versions"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.SimApiRouteOptions.UserInfoRoute != null)
|
if (options.SimApiRouteOptions.UserInfoRoute != null)
|
||||||
{
|
{
|
||||||
logger.LogInformation("注册内置Route: UserInfo => {}", options.SimApiRouteOptions.UserInfoRoute);
|
logger.LogInformation("注册内置Route: UserInfo => {}", options.SimApiRouteOptions.UserInfoRoute);
|
||||||
@@ -480,6 +484,17 @@ public static class SimApiExtensions
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.SimApiRouteOptions.WebConfigRoute != null)
|
||||||
|
{
|
||||||
|
logger.LogInformation("注册内置Route: Logout => {}", options.SimApiRouteOptions.WebConfigRoute);
|
||||||
|
builder.MapControllerRoute(name: "WebConfig", pattern: options.SimApiRouteOptions.WebConfigRoute,
|
||||||
|
defaults: new
|
||||||
|
{
|
||||||
|
controller = "SimApiCommon",
|
||||||
|
action = "WebConfig"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (options.EnableSimApiDoc)
|
if (options.EnableSimApiDoc)
|
||||||
{
|
{
|
||||||
logger.LogInformation("开始配置SimApiDoc...");
|
logger.LogInformation("开始配置SimApiDoc...");
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.OpenApi;
|
||||||
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
|
|
||||||
|
namespace SimApi.SwaggerFilters;
|
||||||
|
|
||||||
|
public class DictionarySchemaFilter : ISchemaFilter
|
||||||
|
{
|
||||||
|
public void Apply(IOpenApiSchema schema, SchemaFilterContext context)
|
||||||
|
{
|
||||||
|
if (!context.Type.IsGenericType || context.Type.GetGenericTypeDefinition() != typeof(Dictionary<,>))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (schema is not OpenApiSchema concrete) return;
|
||||||
|
|
||||||
|
var valueType = context.Type.GetGenericArguments()[1];
|
||||||
|
concrete.Type = JsonSchemaType.Object;
|
||||||
|
concrete.AdditionalPropertiesAllowed = true;
|
||||||
|
concrete.AdditionalProperties = context.SchemaGenerator.GenerateSchema(valueType, context.SchemaRepository);
|
||||||
|
concrete.Properties?.Clear();
|
||||||
|
concrete.Example = null;
|
||||||
|
concrete.Examples?.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user