Redirect Unauthorized Page Access in MVC to Custom View
Asked Answered
D

5

24

I have an MVC website in which access is based on various Roles. Once a user logs into the system they can see navigation to the pages for which they are authorized. However, some users may still try to access pages using a direct URL. If they do, the system automatically redirects them to the Login Page. Instead of the Login Page I want to redirect them to another view (Unauthorized).

Web.Config has the following entry:

    <customErrors mode="On">
      <error statusCode="401" redirect="~/Home/Unauthorized" />
      <error statusCode="404" redirect="~/Home/PageNotFound" />
    </customErrors>
    <authentication mode="Forms">
<forms name="Development" loginUrl="~/Account/Login" cookieless="UseCookies" timeout="120"></forms>
    </authentication>

I have registered these routes in Global.asax.cs as well.

routes.MapRoute(
    name: "Unauthorized",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Unauthorized", id = UrlParameter.Optional }
   );


routes.MapRoute(
    name: "PageNotFound",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "PageNotFound", id = UrlParameter.Optional }
    );

Will it be enough?

Dippold answered 27/2, 2014 at 16:27 Comment(0)
D
22

With following change it is working

public class CustomAuthorize : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        //filterContext.Result = new HttpUnauthorizedResult(); // Try this but i'm not sure
          filterContext.Result = new RedirectResult("~/Home/Unauthorized");
    }

    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        if (this.AuthorizeCore(filterContext.HttpContext))
        {
            base.OnAuthorization(filterContext);
        }
        else
        {
            this.HandleUnauthorizedRequest(filterContext);
        }
    }

}

And then applying on Controller or Action as below:

[CustomAuthorize(Roles = "Admin")]

With above approach I need to revisit all the controller/actions and change the Authorized attribute! Also some testing will be needed.

I am still not sure why Web.Config route not working as same has been explained in MVC Documentation. May be something has changed in MVC 4!

Dippold answered 27/2, 2014 at 17:9 Comment(0)
V
37

After some research I think the easiest answer to this problem is just creating custom authorize, very similar to the one by jbbi (but that one didn't work since the "new HttpUnauthorizedResult()" is internaly automatically redirecting to the login - at least in mvc 5 with identity)

public class CustomAuthorize : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
        {
            //if not logged, it will work as normal Authorize and redirect to the Login
            base.HandleUnauthorizedRequest(filterContext);

        }
        else
        {
            //logged and wihout the role to access it - redirect to the custom controller action
            filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = "Error", action = "AccessDenied" }));
        }
    }
}

and the usage is the same as the default Authorize:

[CustomAuthorize(Roles = "Administrator")]

Then, just to do things right, don't forget to send out the Http code of the error page. e.g like this in the controller.

public ActionResult AccessDenied()
{
    Response.StatusCode = 403;
    return View();
}

It's easy, it works and even I (a .net mvc rookie) understand this.

Note: It doesn't work the same with a 401 code - it will always take over the 401 and internaly redirect it to the login. But in my case is, by definition, the 403 also fitting.

Veron answered 18/8, 2014 at 0:12 Comment(2)
I forgot how I did this that time. Above look good. I will try to implement it and see if it works as intended.Dippold
Make sure to use System.Web.Mvc namespace and not System.Web.Http. they both have HandleUnauthorizedRequest methodCaveman
D
22

With following change it is working

public class CustomAuthorize : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        //filterContext.Result = new HttpUnauthorizedResult(); // Try this but i'm not sure
          filterContext.Result = new RedirectResult("~/Home/Unauthorized");
    }

    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        if (this.AuthorizeCore(filterContext.HttpContext))
        {
            base.OnAuthorization(filterContext);
        }
        else
        {
            this.HandleUnauthorizedRequest(filterContext);
        }
    }

}

And then applying on Controller or Action as below:

[CustomAuthorize(Roles = "Admin")]

With above approach I need to revisit all the controller/actions and change the Authorized attribute! Also some testing will be needed.

I am still not sure why Web.Config route not working as same has been explained in MVC Documentation. May be something has changed in MVC 4!

Dippold answered 27/2, 2014 at 17:9 Comment(0)
B
5

Probably best way to handle this is to create an additional action filter, that redirects the user to the specified error page if he does not belong to the specified role. So, this methods will have both filters applied: [Authorize] (with no roles) to protect from unauthenticated users and redirecting them to the Login Page. And your custom Attribute with the roles. Code SIMILAR to this (not tested):

public class RoleFilterAttribute : ActionFilterAttribute
{
    public string Role { get; set; }
    public override void OnActionExecuting(ActionExecutingContext ctx)
    {
        // Assume that we have user identity because Authorize is also
        // applied
        var user = ctx.HttpContext.User;
        if (!user.IsInRole(Role))
        {
            ctx.Result = new RedirectResult("url_needed_here");
        }
    }
}

Apply both [Authorize] and [RoleFilter] to the actions...

Hope this helps!

Bagging answered 27/2, 2014 at 16:53 Comment(2)
Property "public string Role { get; set; }" how it will know that user belong to particular role(s)? Will it a try though!Dippold
Hi, the property is for storing the role you want to check. So, if you want to protect a method only for "Managers" you could use: [RoleFilter(Role="Manager")] at your action. This example only checks for one role, but extending it to check for N roles (i. e. separated by commas is trivial). The method that really performs the check is IsInRole.Bagging
B
2

I think you should create your own Authorize filter attribute which inherit of the default Authorize filter

public class CustomAuthorize: AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
       filterContext.Result = new HttpUnauthorizedResult(); // Try this but i'm not sure
    }
}
Belsen answered 27/2, 2014 at 16:39 Comment(1)
As other approach is not working, I am choosing this route. Thanks! I will still try to find out why web.config did not worked. Will post any finding here.! Cheers!Dippold
O
0

To redirect-unauthorized-page-access-Asp.net C# -to-custom-view

  1. on page load add this in login.aspx.cs
     protected void Page_Load(object sender, EventArgs e)
        {
            try
            {
                
                txtUsername.Focus();
                if (!IsPostBack)
                {
                    if (Request.IsAuthenticated && !string.IsNullOrEmpty(Request.QueryString["ReturnUrl"]))
                    {
                        Response.Redirect("UnauthorizedAccess.aspx", false);
                        return;
                    }                   
                    Session.Clear();
                    Session.Abandon();

                }                
            }
            catch (Exception ex)
            {
                this.errLogin.Text = ex.Message;                
            }
        }

2)create UnauthorizedAccess.aspx

    <h1>Unauthorized</h1>

        
            <p>Sorry, you are not authorized to access this page</p>
        
           <asp:LinkButton ID="lnkhome" runat="server" CssClass="btn btn-success1" OnClick="lnkhome_Click"
               CausesValidation="false"><span class="fa fa-home"/> Back to Home</asp:LinkButton>
Overcritical answered 30/6, 2020 at 5:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.