http-redirectasp.net-core-mvchttp-status-code-403.net-8.0

ASP.NET Core MVC - Redirect to Access Denied Page on 403


I have a relatively simple ASP.NET Core MVC intranet app that was originally written in .NET Core 2.0, but which I'm trying to update to .NET 8.

I'm not making any other changes to it (yet), all I'm doing right now is trying to get it working in .NET 8. The app is using Integrated Windows authentication along with the Authorize attribute and roles property to implement some basic authorization.

This code is supposed to redirect users who receive a 403 response to my AccessDenied page, and it works in .NET Core 2.0, but isn't working in .NET 8. This code was originally in my Startup class, but I've moved it to the Program class for .NET 8 since I got the impression that seems to be what I probably ought to be doing now.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();
builder.Services.AddAuthentication(IISDefaults.AuthenticationScheme);

var app = builder.Build();

app.UseStatusCodePages(statusCodeContext =>
{
   if (statusCodeContext.HttpContext.Response.StatusCode == 403)
   {
       statusCodeContext.HttpContext.Response.Redirect(statusCodeContext.HttpContext.Request.PathBase + "/AccessDenied");
   }
   return Task.CompletedTask;
});

It just seems to be ignoring the UseStatusCodePages method completely, as far as I can tell. I have to be honest, I'm kind of an amateur programmer so I don't know a lot about the intricacies of ASP.NET Core MVC, so I'm sure I probably copied this code from somewhere online (probably StackOverflow, even) back in 2019. I just can't figure out why it's not working now in .NET 8.

I found other posts with potential solutions, but they either involved things that don't apply here, like using cookies, or they involved adding my own custom middleware, which is a little over my head and seems a little complicated for what used to be relatively simple. I'm hoping I'm just missing something obvious. Thank you very much for your help!


Solution

  • It just seems to be ignoring the UseStatusCodePages method completely, as far as I can tell. I have to be honest, I'm kind of an amateur programmer so I don't know a lot about the intricacies of ASP.NET Core MVC, so I'm sure I probably copied this code from somewhere online (probably StackOverflow, even) back in 2019. I just can't figure out why it's not working now in .NET 8.

    Based on your scenario and description I have tried to reproduce your issue and I was able to find the cause why you were not able to redirect to your access denied page while there's an error 403

    I have seen that you are using wrong order for UseStatusCodePages redirection defination.

    You must need to place UseStatusCodePages between app.UseRouting(); and app.UseAuthentication(); middleware other than, it will always be ignored.

    Correct order:

    app.UseRouting();
    
    app.UseStatusCodePages(async context =>
    {
        var response = context.HttpContext.Response;
    
        if (response.StatusCode == 403 || response.StatusCode == 401)
        {
            response.Redirect("/Users/AccessDenied");
        }
        await Task.CompletedTask;
    });
    app.UseAuthentication();
    

    Access Denied Action:

    public class UsersController : Controller
     {
         
        [AllowAnonymous]
        [HttpGet]
        public IActionResult AccessDenied()
        {
            return View();
        }
    }
    

    Using Middleware:

    Alternatively, if you would like to use middleware, in that case, you could try as following:

    public class AccessDeniedMiddleware
        {
            private readonly RequestDelegate _next;
        
            public AccessDeniedMiddleware(RequestDelegate next)
            {
                _next = next;
            }
        
            public async Task InvokeAsync(HttpContext context)
            {
                await _next(context);
        
                if (context.Response.StatusCode == 401 || context.Response.StatusCode == 403)
                {
                    context.Response.Redirect("/Users/AccessDenied");
                }
              
            }
        }
    

    Note: await _next(context); must be placed before the context checking conditional.

    Middleware order:

    app.UseRouting();
    app.UseMiddleware<AccessDeniedMiddleware>();
    app.UseAuthentication();
    

    Output:

    enter image description here

    I have tested reproducing both StatusCode 401 and 403, you could set your logic as per your requirement.