Files
StoreWeb/Core/MAX.Framework/DependencyInjection/TokenAuthServiceCollectionExtensions.cs
T
2026-10-29 11:34:35 +08:00

73 lines
3.1 KiB
C#

using Asp.Versioning.OpenApi;
using MAX.Framework.Security;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi;
namespace MAX.Framework.DependencyInjection;
public static class TokenAuthServiceCollectionExtensions
{
// Compatibility entry point; authentication no longer uses JWT.
public static IServiceCollection AddStoreHubJwt(this IServiceCollection services, IConfiguration configuration)
=> services.AddStoreHubTokenAuth(configuration);
public static IServiceCollection AddStoreHubTokenAuth(this IServiceCollection services, IConfiguration configuration)
{
services.AddOptions<TokenAuthOptions>().Bind(configuration.GetSection("TokenAuth"))
.Validate(o => o.IdleDays > 0 && o.IdleDays <= 36500 && o.AbsoluteMaxDays > 0 && o.AbsoluteMaxDays <= 36500
&& o.RenewIntervalMinutes > 0 && o.RenewIntervalMinutes < o.IdleDays * 1440
&& o.CacheSeconds >= 0 && o.CacheSeconds <= 86400 && o.MaxDevicesPerUser >= 0,
"TokenAuth 配置无效:有效期必须为正,续期间隔必须小于闲置有效期,缓存和设备数不能为负。")
.ValidateOnStart();
services.AddMemoryCache();
services.AddSingleton(TimeProvider.System);
services.AddHttpContextAccessor();
services.AddSingleton<TokenService>();
services.AddSingleton<ITokenService>(sp => sp.GetRequiredService<TokenService>());
services.AddSingleton<IOnlineUserStore, OnlineUserStore>();
services.AddScoped<ICurrentUser, CurrentUser>();
services.AddAuthentication("Bearer").AddScheme<AuthenticationSchemeOptions, TokenAuthenticationHandler>("Bearer", _ => { });
services.Configure<VersionedOpenApiOptions>(options =>
{
// 在 OpenAPI 文档中声明 Bearer 安全方案
options.Document.AddDocumentTransformer((document, _, _) =>
{
document.Components ??= new OpenApiComponents();
document.Components.SecuritySchemes ??= new Dictionary<string, IOpenApiSecurityScheme>();
document.Components.SecuritySchemes.TryAdd("Bearer", new OpenApiSecurityScheme
{
Type = SecuritySchemeType.Http,
Scheme = "bearer",
BearerFormat = "Opaque",
Description = "登录接口返回的 accessToken,直接粘贴令牌内容即可(无需手动加 Bearer 前缀)。",
});
return Task.CompletedTask;
});
// 仅对标记了 [Authorize] 的接口声明需要携带令牌
options.Document.AddOperationTransformer((operation, context, _) =>
{
IList<object> metadata = context.Description.ActionDescriptor.EndpointMetadata;
bool requiresAuth = metadata.OfType<IAuthorizeData>().Any()
&& !metadata.OfType<IAllowAnonymous>().Any();
if (requiresAuth)
{
operation.Security =
[
new OpenApiSecurityRequirement
{
[new OpenApiSecuritySchemeReference("Bearer", context.Document, "")] = [],
},
];
}
return Task.CompletedTask;
});
});
return services;
}
}