Dot-Net

如何更改狀態程式碼並從失敗的 AuthorizationHandler 策略添加消息

  • November 10, 2021

處理實現自定義策略的 .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 的行為的文件可以在下面找到:

https://docs.microsoft.com/en-us/aspnet/core/security/authorization/customizingauthorizationmiddlewareresponse?view=aspnetcore-5.0

我的程式碼最終看起來像這樣:

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>();

引用自:https://stackoverflow.com/questions/48889688