Dot-Net
如何更改狀態程式碼並從失敗的 AuthorizationHandler 策略添加消息
處理實現自定義策略的 .net 核心應用程序。
假設我們有一個非常簡單的自定義策略:
internal class RequireNamePolicy : AuthorizationHandler<RequireNameRequirement>, IAuthorizationRequirement { protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, RequireNameRequirement requirement) { var nameClaim = context.User.Claims.FirstOrDefault(c => c.Type == Claims.Name); if (nameClaim != null && nameClaim.Value == "Chimney Spork") { context.Succeed(requirement); } else { context.Fail(); } return Task.CompletedTask; } } internal class RequireNameRequirement : IAuthorizationRequirement { }現在假設聲明不存在,所以我們點擊 context.Fail()。預設響應是沒有消息正文的 403。
我的問題是,我們將在哪裡更改狀態程式碼(更改為 401)並返回一條說明問題的消息(即聲明不存在)?
context.Resource as AuthorizationFilterContext 在 net core 3.1 中為空
最後我將方法重寫為:
public class SysUserAuthHandler : AuthorizationHandler<SysUserAuthRequirement> { private readonly IFetchLoginUser fetchUser; private readonly IHttpContextAccessor httpContextAccessor; public SysUserAuthHandler( IFetchLoginUser fetchLoginUser, IHttpContextAccessor httpContextAccessor ) { fetchUser = fetchLoginUser; this.httpContextAccessor = httpContextAccessor; } protected override Task HandleRequirementAsync( AuthorizationHandlerContext context, SysUserAuthRequirement requirement ) { var httpContext = httpContextAccessor.HttpContext; byte[] bytes; string msg; if (!string.IsNullOrWhiteSpace( context.User.Identity.Name )) { var myUser = fetchUser.LoadUser( context.User.Identity.Name, SystemEnum.FooSytem); if ((myUser.Auth & requirement.Auth) == requirement.Auth) { context.Succeed( requirement ); return Task.CompletedTask; } msg = requirement.Auth switch { 1 => "You don't have Auth of Maker", 2 => "You don't have Auth of Checker", 4 => "You don't have Auth of Admin", 8 => "You don't have Auth of Operator", _ => "You don't have Auth" }; } else { msg = "User Invalid, Please check your login status or login again"; } bytes = Encoding.UTF8.GetBytes( msg ); httpContext.Response.StatusCode = 405; httpContext.Response.ContentType = "application/json"; httpContext.Response.Body.WriteAsync( bytes, 0, bytes.Length ); //context.Succeed( requirement ); return Task.CompletedTask; } } public class SysUserAuthRequirement : IAuthorizationRequirement { public long Auth { get; private set; } public SysUserAuthRequirement( long auth ) { Auth = auth; } }不要忘記在啟動中添加這一行
services.AddHttpContextAccessor();
自定義 AuthorizationMiddleware 的行為的文件可以在下面找到:
我的程式碼最終看起來像這樣:
public class GuidKeyAuthorizationMiddlewareResultHandler : IAuthorizationMiddlewareResultHandler { private readonly AuthorizationMiddlewareResultHandler DefaultHandler = new AuthorizationMiddlewareResultHandler(); public async Task HandleAsync( RequestDelegate requestDelegate, HttpContext httpContext, AuthorizationPolicy authorizationPolicy, PolicyAuthorizationResult policyAuthorizationResult) { if (policyAuthorizationResult.Challenged && !policyAuthorizationResult.Succeeded && authorizationPolicy.Requirements.Any(requirement => requirement is GuidKeyRequirement)) { httpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; return; } // Fallback to the default implementation. await DefaultHandler.HandleAsync(requestDelegate, httpContext, authorizationPolicy, policyAuthorizationResult); } }啟動.cs:
services.AddSingleton<IAuthorizationMiddlewareResultHandler, GuidKeyAuthorizationMiddlewareResultHandler>();