Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change status code & add message from failed AuthorizationHandler policy

Working on a .net core app implementing a custom policy.

Let's say we have a very simple custom policy:

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
{

}

Now let's say the claim doesn't exist, so we hit context.Fail(). The default response is a 403 with no message body.

My question is, where would we change the status code (to 401) and return a message that states the problem (ie claim not present)?

like image 492
sdrevk Avatar asked Feb 20 '18 16:02

sdrevk


People also ask

How do I change my status code on Fastapi?

You can declare a parameter of type Response in your path operation function (as you can do for cookies and headers). And then you can set the status_code in that temporal response object. And then you can return any object you need, as you normally would (a dict , a database model, etc).

What are 200 status codes?

The 200 status code is by far the most common returned. It means, simply, that the request was received and understood and is being processed. A 201 status code indicates that a request was successful and as a result, a resource has been created (for example a new page).

What is HTTP delete status code?

DELETE API Response Codes. A successful response of DELETE requests SHOULD be an HTTP response code 200 (OK) if the response includes an entity describing the status. The status should be 202 (Accepted) if the action has been queued.

How to set a different HTTP status code in the response?

To set a different HTTP Status Code in the Response, do the following: Go to Manage Dependencies... and add the SetStatusCode action of the HTTPRequestHandler extension. Use the SetStatusCode action in your REST API Method or callback flow right before the end node. Set its "StatusCode" property to the desired status code.

What does the status �response� <strong>code� mean?

This response code means the returned meta-information is not exactly the same as is available from the origin server, but is collected from a local or a third-party copy. This is mostly used for mirrors or backups of another resource. Except for that specific case, the "200 OK" response is preferred to this status. 204 No Content

How do I change the status code of my Rest API?

Use the SetStatusCode action in your REST API Method or callback flow right before the end node. Set its "StatusCode" property to the desired status code. Was this article useful?

Can I change the status code after I disable buffering?

AFAIK, if you disable buffering, the web server starts sending the response immediately. Given an HTTP response starts with a status line containing the status code, you can't change the status code after you've started sending a response. in your controller ?


Video Answer


2 Answers

The documentation for Customize the behavior of AuthorizationMiddleware can be found below:

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

My code finally looked like this:

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

Startup.cs:

services.AddSingleton<IAuthorizationMiddlewareResultHandler,
    GuidKeyAuthorizationMiddlewareResultHandler>();
like image 144
Ogglas Avatar answered Oct 16 '22 20:10

Ogglas


context.Resource as AuthorizationFilterContext is null in net core 3.1

Finally I rewrite the method to this:

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

  }

Do not forget add this line in Startup

    services.AddHttpContextAccessor();
like image 9
Garrod Ran Avatar answered Oct 16 '22 19:10

Garrod Ran