51 lines
2.6 KiB
C#
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));
|
|
}
|
|
}
|