Search code examples
c#asp.net-coreasp.net-core-2.2asp.net-core-identity

ASP.NET Core Identity: How to redefine Forbid processing


Situation: I return Forbid() from the PageModel and this initiates response with Redirect (302) to /AccessDenied&returnUrl=...

Here I specify the path:

 // configuration was used
 serviceCollection.ConfigureApplicationCookie(options =>
 {
     options.AccessDeniedPath = new PathString("/AccessDenied");
 });

But how can I totally override the "redirect response" creation and specify my own GET parameters (something as returnUrl) or redefine the returnUrl value (I want to pass my own value that is saved in custom request feature)?

Alternatively instead of returning Forbid() I can redirect to AccessDenied manually. But I would like to stay with Forbid() for demonstrativeness and consistency.

UPDATE: this doesn't work either

public void ConfigureServices(IServiceCollection serviceCollection)
    {
        serviceCollection.ConfigureApplicationCookie(options =>
        {
            //options.AccessDeniedPath = new PathString("/AccessDenied");
            options.Events.OnRedirectToAccessDenied = context =>
            {
                context.Response.Redirect("/AccessDenied&t=100");
                return Task.CompletedTask;
            };
        });

        // need for password reset functionality
        serviceCollection.AddDbContext<WebUserDbContext>(optionsBuilder =>
            optionsBuilder.UseSqlServer(ApplicationSettings.WebUserStorageConfiguration.ConnectionString));

        serviceCollection.AddIdentity<WebUser, IdentityRole<int>>( options =>
            {
                options.SignIn.RequireConfirmedEmail = true;
            })
            .AddEntityFrameworkStores<WebUserDbContext>()
            .AddDefaultTokenProviders();

        // generally it is a version of routin by 

         serviceCollection.AddMvc()
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    }

P.S. This is service site that do not need identity to authenticate but manage users records. So MS Identity Lib authentication is not enabled for the site. Identity types just were putted to the container because I need specific Identity API functionality: "reset password". It is idiotic situation: UserManager alike Identity API classes are so complex that it is impossible to cunstruct them other way than get from DI/container. Please do not share this MS DI madness in your APIs.

It is interesting that without serviceCollection.AddIdentity browser recieve "Error 500" on .Forbid() and breakpoint still doesn't stop on context.Response.Redirect("/AccessDenied&t=100");


Solution

  • The redirect to the configured AccessDeniedPath is the default behavior for the cookie authentication. It will automatically add a returnUrl parameter which defaults to the current URL. If you specify a RedirectUri inside of the authentication properties, that URL will be used instead.

    For example, inside of a controller:

    return Forbid(new AuthenticationProperties
    {
        RedirectUri = Url.Action("ActionAfterForbid"),
    });
    

    This will basically generate a redirect to the URL {AccessDeniedPath}?returnUrl=/exampleController/ActionAfterForbid.

    If you need more customization, you can also override the RedirectToAccessDenied event of the cookie authentication options:

    services.ConfigureApplicationCookie(options =>
    {
         options.Events.OnRedirectToAccessDenied = context =>
         {
             // context.Options.AccessDeniedPath would be the configured path
             // context.RedirectUri is the passed or automatically set up redirect URI
             // context.HttpContext is the HttpContext if you want to modify features
    
             // default behavior is basically this:
             context.Response.Redirect(context.RedirectUri);
             return Task.CompletedTask;
         };
    });
    

    There, you can do whatever else you want to do.

    Note that you will have to call ConfigureApplicationCookie after the call to AddIdentity. This is because the latter will configure the application cookie itself already with some default values, so if you configure the authentication events, they will be overwritten by AddIdentity. Instead, you want to overwrite the defaults with ConfigureApplicationCookie so you have to call that one afterwards.