Reputation: 81
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)
Upvotes: 3
Views: 489
Reputation: 239440
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:
Upvotes: 0
Reputation: 21
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
Upvotes: 0