Using an MVC4 application that uses .NET 4.5 and IIS 8. Is there a way to return a custom unauthorised page AND a 401 result, when a permission check fails?
I am also using Forms authentication and want a redirect to the login page when a user isn't logged in, but a redirect to an unauthorised page when a user does not have the valid permission (i.e. Admin).
I also have to be careful of redirecting and then achieving a 200/301 result on successful redirect.
I need to return 401 status code and stay on the current page, whilst also returning the custom unauthorized page.
I have an Error controller that returns an unauthorized view:
[ActionName("unauthorised")]
public ActionResult Http401() {
Response.StatusCode = 401;
Response.StatusDescription = "Unauthorised";
Response.SuppressFormsAuthenticationRedirect = true;
return View("unauthorised");
}
And I have some methods that I am using to try and invoke a 401 if a check for a permission fails:
/// <summary>Method to invoke when user attempts action without relevant permission</summary>
/// <param name="httpContext">the httpcontext</param>
/// <returns>empty result</returns>
public ActionResult InvokeHttp401(HttpContextBase httpContext) {
Transfer("/error/unauthorised");
return new EmptyResult();
}
private void Transfer(string url) {
var uriBuilder = new UriBuilder(Request.Url.Scheme, Request.Url.Host, Request.Url.Port, Request.ApplicationPath); // Create URI builder
uriBuilder.Path += url; // Add destination URI
string path = Server.UrlDecode(uriBuilder.Uri.PathAndQuery); // Because UriBuilder escapes URI decode before passing as an argument
this.HttpContext.RewritePath(path, false); // Rewrite path
HttpContext.Server.TransferRequest(path, true);
}
Note: I am using Server.TransferRequest so that I can try and return the 401 result on the current url, without causing any redirect. I am checking permission in a regular ActionResult as follows:
[Authorize]
public ActionResult MyMethod() {
if (!UserHasPermission(Admin))
return InvokeHttp401(HttpContext);
......
Where the authorize tag will redirect to login if a user is not logged in, other a permissions check is made.
With the above setup, I am able to return a 401 result and stay on the current url, but the IIS 401 error is displayed instead of my current page.
I have also tried to set the following in my web.config file:
<httpErrors errorMode="DetailedLocalOnly" existingResponse="Replace">
.....
<error statusCode="401" responseMode="ExecuteURL" path="/Error/unauthorised" />
</httpErrors>
But this makes no difference. I am able to get the custom unauthorised page to appear if I do not set the status code in my Http401 ActionResult, but it is just returned with a 200 result then.
I have looked at the posts on this question (particularly Timothy's answer which extended the authorize tags), but was unable to get any of this working without similar errors as already described.
Can anyone help here?