Role Based Access Control in ASP.NET MVC

Role Based Access Control in MVC is pretty straight forward. There is also a way to do claims access control, but the most common way is based on roles.

To show or hide action links in a view depending on the user role we can use the following Razor syntax on your Views:

@if (User.IsInRole("Administrator"))
{
...
}

On the controllers, to avoid access to an action if the user types in the URL directly on the browser, we can annotate the action with the Role check tags:

For example the following code would limit access to any actions on the AdministrationControllerto users who are a member of the Administrator group.

[Authorize(Roles = "Administrator")]
public class AdministrationController : Controller
{
}

You can specify multiple roles as a comma separated list;

[Authorize(Roles = "HRManager,Finance")]
public class SalaryController : Controller
{
}

This controller would be only accessible by users who are members of the HRManager role or theFinance role.

If you apply multiple attributes then an accessing user must be a member of all the roles specified; the following sample requires that a user must be a member of both the PowerUser andControlPanelUser role.

[Authorize(Roles = "PowerUser")]
[Authorize(Roles = "ControlPanelUser")]
public class ControlPanelController : Controller
{
}

You can further limit access by applying additional role authorization attributes at the action level;

[Authorize(Roles = "Administrator, PowerUser")]
public class ControlPanelController : Controller
{
    public ActionResult SetTime()
    {
    }
 
    [Authorize(Roles = "Administrator")]
    public ActionResult ShutDown()
    {
    }
}

In the previous code snippet members of the Administrator role or the PowerUser role can access the controller and the SetTime action, but only members of the Administrator role can access the ShutDown action.

You can also lock down a controller but allow anonymous, unauthenticated access to individual actions.

[Authorize]
public class ControlPanelController : Controller
{
    public ActionResult SetTime()
    {
    }
 
    [AllowAnonymous]
    public ActionResult Login()
    {
    }
}

There is also a way to use Policies for limiting access, but to keep it simple, since we already have the roles defined, we can use the common RBAC for now until we need something more complex.

When the user requests the URL directly they will get a nasty 401 Unauthorized page from IIS if their request is not Authorized.

The Razor code above can be used on the views to grey out the links if the User doesn’t have permissions, but if they had bookmarked the page or type the URL, they will receive a 401 page.

We can give them a more friendly page explaining they don’t have permissions to access the resources requested and link them to a request access page.

This is what could be done:

For a 401 you will probably be seeing the standard 401 Unauthorised page, even if you have added 401 to the customerrors section in your web.config. When using IIS and Windows Authentication the check happens before ASP.NET MVC even sees the request

By editing the Global.asax file you can redirect to a route created for 401 errors, sending the user to the “Unauthorized to see this” view (friendly page).

In the Global.asax:

void Application_EndRequest(object sender, System.EventArgs e)
{
    // If the user is not authorised to see this page or access this function, send them to the error page.
    if (Response.StatusCode == 401)
    {
        Response.ClearContent();
        Response.RedirectToRoute("ErrorHandler", (RouteTable.Routes["ErrorHandler"] as Route).Defaults);
    }
}

and in the Route.config:

     routes.MapRoute(
               "ErrorHandler",
               "Error/{action}/{errMsg}",
                new { controller = "Error", action = "Unauthorized", errMsg = UrlParameter.Optional }
     );

and in the controller:

public ViewResult Unauthorized()
{
        //Response.StatusCode = 401; // Do not set this or else you get a redirect loop
        return View();
}

Voila!

Happy coding.