Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.net core - How to return 403 on AuthorizationHandler?

I implemented my custom AuthorizationHandler. On that i check i the user can resolved and is active.

If the user isn't active then i would like to return an 403 status.

protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, ValidUserRequirement requirement)
{
    var userId = context.User.FindFirstValue( ClaimTypes.NameIdentifier );

    if (userId != null)
    {
        var user = await _userManager.GetUserAsync(userId);

        if (user != null)
        {
            _httpContextAccessor.HttpContext.AddCurrentUser(user);

            if (user.Active)
            {
                context.Succeed(requirement);
                return;
            }
            else
            {
                _log.LogWarning(string.Format("User ´{1}´ with id: ´{0} isn't active", userId, user.UserName), null);
            }
        }
        else
        {
            _log.LogWarning(string.Format("Can't find user with id: ´{0}´", userId), null);
        }
    } else
    {
        _log.LogWarning(string.Format("Can't get user id from token"), null);
    }

    context.Fail();

    var response = _httpContextAccessor.HttpContext.Response;
    response.StatusCode = 403;

}

But i receive a 401. Can you please help me?

like image 869
Flo Avatar asked Aug 03 '18 08:08

Flo


2 Answers

Could you check that on the end of your function? I'm using that in my custom middleware to rewrite status code to 401 in some cases but in your scenario should also work

var filterContext = context.Resource as AuthorizationFilterContext;
var response = filterContext?.HttpContext.Response;
response?.OnStarting(async () =>
{
    filterContext.HttpContext.Response.StatusCode = 403;
//await response.Body.WriteAsync(message, 0, message.Length); only when you want to pass a message
});
like image 181
Jaume Avatar answered Oct 21 '22 13:10

Jaume


According to the Single Responsibility Principle , we should not use the HandleRequirementAsync() method to redirect reponse , we should use middleware or Controller to do that instead . If you put the redirect logic in HandleRequirementAsync() , how about if you want to use it in View page ?

You can remove the redirection-related code to somewhere else (outside) , and now you inject an IAuthorizationService to authorize anything as you like , even a resource-based authorization :

public class YourController : Controller{

    private readonly IAuthorizationService _authorizationService;
    public YourController(IAuthorizationService authorizationService)
    {
        this._authorizationService = authorizationService;
    }

    [Authorize("YYY")]
    public async Task<IActionResult> Index()
    {
        var resource  /* = ... */ ;
        var x = await this._authorizationService.AuthorizeAsync(User,resource , "UserNameActiveCheck");

        if (x.Succeeded)
        {
            return View();
        }
        else {
            return new StatusCodeResult(403);
        }
    }

}
like image 44
itminus Avatar answered Oct 21 '22 12:10

itminus