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

51 lines
2.6 KiB
C#

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<AuthenticationSchemeOptions> options,
ILoggerFactory logger, UrlEncoder encoder, ITokenService tokens,
IConfiguration configuration, IHostEnvironment environment)
: AuthenticationHandler<AuthenticationSchemeOptions>(options, logger, encoder)
{
protected override async Task<AuthenticateResult> 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<bool>("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));
}
}