Permission-based access in ASP.NET MVC

I recently read an interesting blog about implementing Role-based access in MVC using custom attributes.  I have implemented a similar strategy for Permission-based access by using the session object.

Storing the permissions

I usually define a user’s permissions as an enumeration and then simply store this as an integer in the database.  You might need permissions to be defined at a group or role-level, but in most cases this will do what is required.  YAGNI!

[Flags]
public enum Permissions
{
    View                 = (1 << 0),
    Add                  = (1 << 1),
    Edit                 = (1 << 2),
    Delete               = (1 << 3),
    Admin                = (View | Add | Edit | Delete)
}

This is the set of permissions I’m going to use for specifying access rights on my actions.

Store the user object in the session

We’re going to need access to the current user’s permissions if we want to determine if the current user has the necessary permissions to perform a certain action.  I find the easiest thing to do is to simply store the current user in the session.  I’ve had some lively debates around this – the best argument against this being that any changes to the user object will cause all users to lose their sessions.  While this is a valid argument, I prefer doing the simplest thing that could possibly work.  YAGNI!

public ActionResult Authenticate(string username, string password)
{
    var user = authenticationService.Authenticate(username, password);
    Session["User"] = user;
                
    return RedirectToAction("Somewhere", "Else");   
}

Create a custom attribute for authorizing access

The last step is to create a custom attribute for authorizing access to our actions.

public class PermissionsAttribute : ActionFilterAttribute
{
    private readonly Permissions required;

    public PermissionsAttribute(Permissions required)
    {
        this.required = required;
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var user = filterContext.HttpContext.Session.GetUser();
        if (user == null)
        {
            //send them off to the login page

            var url = new UrlHelper(filterContext.RequestContext);
            var loginUrl = url.Content("~/Home/Login"); 
            filterContext.HttpContext.Response.Redirect(loginUrl, true);    
        }
        else
        {
            if (!user.HasPermissions(required))
            {
                throw new AuthenticationException("You do not have the necessary permission to perform this action");
            }
        }
    }
}

And that’s all we need.  Now we can specify the necessary permissions on each controller action.

[Permissions(Permissions.View)]
public ActionResult Index()
{
    // ...

}

Happy coding.