简体   繁体   中英

Getting a custom page to show without changing the url

I want to show a page when users try to access something that they shouldn't. This restriction is check in custom middleware. When the middleware returns a false and the new controller gets called I don't want the client side url to change.

This is my middleware check:

public async Task Invoke(HttpContext context, IAutorisationService service)
        {
            var user = service.CreateUserModel(context);
            var page = service.CreatePageModel(context);
            context.Items.Add("CurrentUser", user);

            if (service.UserAllowedToPage(user, page))
                await _next.Invoke(context);
            else
            {
                context.Response.Redirect("/Error/CustomError");
            }
        }

This is the error controller:

public IActionResult CustomError()
        {
            if (!HttpContext.Items.TryGetValue("CurrentUser", out var o) || !(o is UserModel userModel))
            {
                return View();
            }

            if (userModel.IsSuperUser)
            {
                return View();
            }

The views returned here all work fine.

This is my startup.cs (where I'm struggling now):

app.UseMvc(routes =>
            {
                //routes.MapRoute(
                    //name: "ErrorRoute",
                    //template: "{controller=Error}",
                    //defaults: new {controller = "Error", action = "CustomError"});

                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");

            });

I just can't seem to get it right with any of the combinations I find on the web.

Update

Ok so I'm not getting any further with the policies. I'll try to explain my situation a bit better: I have a custom middleware at the end of the pipeline (just before app.UseMvc ) That middleware has a async Task Invoke method that calls a boolean operator in a different class. Now if the boolean returns true the middleware task does: await _next.Invoke(HttpContext) and I want the middleware to excecute an exception if that boolean returns false. And when the exception is thrown I want the: app.UseExceptionHandler("/Error/CustomError"); or the app.UseStatusCodePagesWithReExecute("/Error/CustomError"); to catch it and activate the CustomError action in the ErrorController to then return a custom view. Is this even possible? (Sorry if my first question wasn't complete)

hi you can return error view using

return View("Error")

you can check what ever you need and if something is wrong instead of the main view you can return the error view

You cannot redirect to a page, without changing the URL. The redirect actually happens client-side. The server simply sends a 302 response with a Location header containing the alternate URL. It is the client's responsibility to actually make a request for that alternate URL, which is what browsers do by default. As a result, the browser will literally be requesting /Error/CustomError .

What you need to do is return the actual error response directly from the middleware, so that the URL stays what it is. However, middleware is the wrong approach here, actually.

Instead, you should be using the built-in authorization framework. You can apply custom policies to controllers/actions by implementing requirements and handlers and then referencing the policy with the Authorize attribute:

[Authorize(Policy = "MyPolicy")]
public IActionResult MyProtectedAction()

Then, when the user fails to meet the policy requirements, they'll fall through into the exception handling middleware, where you can tie in your custom view via configuring app.UseStatusCodePagesWithReExecute :

public class Startup
{
    ...

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseStatusCodePagesWithReExecute("/error/{0}");

        ...
    }
}

That will then execute the controller and action defined for the /error/{0} route, without affecting the URL (the "ReExecute" part). The {0} bit will be replaced with the the HTTP status code, which will be 401 Unauthorized . So you can literally have an action tied to /error/401 or a catch all action with a route like /error/{statusCode} and then branch inside on the status code to handle multiple different error types. For what it's worth, this is also how you'd provide custom 404 pages, 500 pages, etc.

For more information see:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM