如何更改状态代码并从失败的 AuthorizationHandler 策略添加消息

sdr*_*evk 8 .net asp.net-core

使用 .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
{

}
Run Code Online (Sandbox Code Playgroud)

现在假设声明不存在,所以我们点击 context.Fail()。默认响应是没有消息正文的 403。

我的问题是,我们将在哪里更改状态代码(到 401)并返回说明问题的消息(即声明不存在)?

Ogg*_*las 10

自定义 AuthorizationMiddleware 行为的文档可以在下面找到:

https://learn.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);
    }
}
Run Code Online (Sandbox Code Playgroud)

启动.cs:

services.AddSingleton<IAuthorizationMiddlewareResultHandler,
    GuidKeyAuthorizationMiddlewareResultHandler>();
Run Code Online (Sandbox Code Playgroud)


Gar*_*Ran 7

context.Resource as AuthorizationFilterContext 在 net core 3.1 中为 null

最后,我将方法重写为:

  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;
    }

  }
Run Code Online (Sandbox Code Playgroud)

不要忘记在启动中添加这一行

    services.AddHttpContextAccessor();
Run Code Online (Sandbox Code Playgroud)


Ram*_*nas -1

这尚未实施。您可以在这里跟进此事。一种可能的解决方法是:

internal class RequireNamePolicy : AuthorizationHandler<RequireNameRequirement>, IAuthorizationRequirement
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, RequireNameRequirement requirement)
    {
        var authorizationFilterContext = context.Resource as AuthorizationFilterContext;

        var nameClaim = context.User.Claims.FirstOrDefault(c => c.Type == Claims.Name);
        if (nameClaim != null && nameClaim.Value == "Chimney Spork")
        {
            context.Succeed(requirement);
        }
        else
        {
            authorizationFilterContext.Result = new JsonResult("Custom message") { StatusCode = 401 };
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}
Run Code Online (Sandbox Code Playgroud)