Elsassmania
Elsassmania

Reputation: 175

ASP.NET Core Identity 2.0 - Return 401 status code to ajax function

I have a ASP.NET Core Application where I use Identity 2.0. I'm trying to return a 401 status code when a user isn't logged in (or 403 when he isn't authorize) but the different functions returns only a 302 code...

I setted up for my application needs :

My RequiresPermission is a class which inherit of TypeFilterAttribute and have a function which seems to be useful to set the different returned results :

 public async Task OnResourceExecutionAsync(ResourceExecutingContext context,
                                                   ResourceExecutionDelegate next)
        {
            var principal = new CustomPrincipal(_PermissionProvider, context.HttpContext.User.Identity);
            bool isInOneOfThisRole = false;
            foreach (var item in _requiredPermissions.RequiredPermissions)
            {
                if (principal.IsInRole(item))
                {
                    isInOneOfThisRole = true;
                }
            }

            if (isInOneOfThisRole == false)
            {
                if (principal.Identity.IsAuthenticated)
                {
                    context.Result = new UnauthorizedResult();
                }
                else
                {
                    context.Result = new RedirectResult("~/Connexion/Login");
                }

                await context.Result.ExecuteResultAsync(context);
            }
            else
            {
                await next();
            }
        }

I've tried a ton of suggestions but nothing seems to work like :

services.ConfigureApplicationCookie(options =>
{
    options.Events.OnRedirectToLogin = context =>
    {
        context.Response.StatusCode = 401;    
        return Task.CompletedTask;
    };
});

This solution is not a good solution for my because it redirect ajax AND non-ajax methods which broke my other redirection...

I also tried to override the AuthorizeAttribute class with a class I found on the web. This class seems to be what I want but it doesn't work to ASP.Net Core...

using Microsoft.AspNetCore.Authorization;
using System.Net;

public class ApplicationAuthorizeAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        var httpContext = filterContext.HttpContext;
        var request = httpContext.Request;
        var response = httpContext.Response;
        var user = httpContext.User;

        if (request.IsAjaxRequest())
        {
            if (user.Identity.IsAuthenticated == false)
                response.StatusCode = (int)HttpStatusCode.Unauthorized;
            else
                response.StatusCode = (int)HttpStatusCode.Forbidden;

            response.SuppressFormsAuthenticationRedirect = true;
            response.End();
        }

        base.HandleUnauthorizedRequest(filterContext);
    }
}

Have you an idea to solve my problem ? Or maybe there is something I do wrong.

Upvotes: 2

Views: 1790

Answers (1)

Elsassmania
Elsassmania

Reputation: 175

Thanks to Brad, I found the solution and it was so stupid...

I don't need the ApplicationAuthorizeAttribute class as I already have my RequiresPermissionAttribute class.

The problem was just in my function OnResourceExecutionAsync() :

  • I returned the wrong code when the user hadn't the right (Unauthorized instead of Forbid result)
  • When my user wasn't logged, I returned a redirectResult to my Login page instead of a StatusResult. I changed it for an UnauthorizedResult().

Changed part of my function :

            if (isInOneOfThisRole == false)
            {
                if (principal.Identity.IsAuthenticated)
                {
                    context.Result = new ForbidResult();
                }
                else
                {
                    context.Result = new UnauthorizedResult();
                }

                await context.Result.ExecuteResultAsync(context);
            }
            else
            {
                await next();
            }

And I already have a function in my ajax to catch the different status code :

$(document).ajaxError(function (xhr, props) {
    if (props.status == 403) {
        window.location = window.location.protocol + '//' + window.location.host + "/Connexion/AccessDenied";
    } else if (props.status == 401) {
        window.location = window.location.protocol + '//' + window.location.host + "/Connexion/Login";
    }
});

And everything works nicely !

Upvotes: 2

Related Questions