using System.Text.Encodings.Web; using MAX.Framework.Dtos; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using System.Security.Claims; namespace MAX.Framework.Security; public sealed class TokenAuthenticationHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ITokenService tokens, IConfiguration configuration, IHostEnvironment environment) : AuthenticationHandler(options, logger, encoder) { protected override async Task HandleAuthenticateAsync() { var header = Request.Headers.Authorization.ToString(); if (!header.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) return AuthenticateResult.NoResult(); var token = header[7..].Trim(); // 固定凭据仅供开发调试,生产环境即使误开启配置也不能使用。 var development = configuration.GetSection("TokenAuth:DevelopmentToken"); if (environment.IsDevelopment() && development.GetValue("Enabled") && !string.IsNullOrWhiteSpace(development["Token"]) && !string.IsNullOrWhiteSpace(development["UserName"]) && string.Equals(token, development["Token"], StringComparison.Ordinal)) { var identity = new ClaimsIdentity([ new Claim(JwtClaimTypes.UserName, development["UserName"]!), new Claim(JwtClaimTypes.NickName, "开发测试用户")], Scheme.Name); return AuthenticateResult.Success(new AuthenticationTicket(new ClaimsPrincipal(identity), Scheme.Name)); } var principal = await tokens.ValidateTokenAsync(token); return principal == null ? AuthenticateResult.Fail("登录已失效,请重新登录") : AuthenticateResult.Success(new AuthenticationTicket(principal, Scheme.Name)); } protected override Task HandleChallengeAsync(AuthenticationProperties properties) { Response.StatusCode = 401; Response.Headers.WWWAuthenticate = "Bearer"; return Response.WriteAsJsonAsync(ApiResult.Fail("未授权:请先登录或携带有效的访问令牌", 401)); } protected override Task HandleForbiddenAsync(AuthenticationProperties properties) { Response.StatusCode = 403; return Response.WriteAsJsonAsync(ApiResult.Fail("禁止访问:当前账号没有权限执行该操作", 403)); } }