滑动续期与自动刷新:

Web:访问令牌 10 分钟;活跃时自动轮换刷新令牌;连续无操作 30 分钟后清除登录并跳转登录页。
App:会话窗口 3 天;打开 App、恢复前台或请求接口时自动刷新并重新顺延 3 天。
普通登录和 SSO 使用同一策略。
刷新令牌只以 SHA-256 摘要入库,每次刷新都会轮换,旧令牌无法再次使用;退出登录会吊销刷新令牌。
网络临时故障不会误清登录状态,多标签页同时刷新也做了竞争处理。
This commit is contained in:
2026-08-03 19:20:39 +08:00 Unverified
parent 6bee29a351
commit 5ec62a03ca
24 changed files with 6986 additions and 75 deletions
+19
View File
@@ -384,6 +384,14 @@ if (Encoding.UTF8.GetByteCount(jwtOptions.Key) < 32 ||
throw new InvalidOperationException(
"Jwt:Key 必须配置为至少 32 字节的随机生产密钥,不能使用示例值。");
}
if (jwtOptions.AccessTokenMinutes is < 1 or > 30 ||
jwtOptions.WebIdleMinutes is < 5 or > 1440 ||
jwtOptions.AppIdleMinutes is < 60 or > 43200 ||
jwtOptions.AccessTokenMinutes > jwtOptions.WebIdleMinutes)
{
throw new InvalidOperationException(
"Jwt 访问令牌或 Web/App 空闲有效期配置超出允许范围。");
}
builder.Services.Configure<JwtOptions>(
builder.Configuration.GetSection(JwtOptions.SectionName));
@@ -391,6 +399,7 @@ builder.Services.Configure<SsoOptions>(
builder.Configuration.GetSection(SsoOptions.SectionName));
builder.Services.AddHttpContextAccessor();
builder.Services.AddScoped<ITokenService, TokenService>();
builder.Services.AddScoped<IAuthSessionService, AuthSessionService>();
builder.Services.AddScoped<ICurrentUserDataScope, CurrentUserDataScope>();
builder.Services.AddScoped<DatabaseInitializer>();
builder.Services.AddScoped<DemoDataSeeder>();
@@ -506,6 +515,16 @@ builder.Services.AddRateLimiter(options =>
QueueLimit = 0,
AutoReplenishment = true
}));
options.AddPolicy("token-refresh", context =>
RateLimitPartition.GetFixedWindowLimiter(
context.Connection.RemoteIpAddress?.ToString() ?? "unknown",
_ => new FixedWindowRateLimiterOptions
{
PermitLimit = 600,
Window = TimeSpan.FromMinutes(1),
QueueLimit = 0,
AutoReplenishment = true
}));
options.AddPolicy("official-verification", context =>
RateLimitPartition.GetFixedWindowLimiter(
context.Connection.RemoteIpAddress?.ToString() ?? "unknown",