Role Based Access Control in MVC

By | December 16

Currently I am looking at access control systems, and how best to integrate them with MVC framework. While this framework already provides support for role based access control (RBAC), using the membership classes. I need to implement this on a legacy database, and some how integrate the old system with forms authentication. This post is about how I realised this, and acts a potential solution. If you can think of a better way, of find any devastating flaws, let me know. ;-)

The scenario is simple, we have four roles defined for the system. They are Students, Graduates, Staff and Administrators. Some staff can be graduates, (or even Students). Administrators are, of course staff! So how you model this? We already know of one bitwise trick from Michal’s post, so let us see how we can use bitwise operations to make this a reality!

First let us revise the results of the bitwise AND operations. You can check Wikipedia for full details.

1 & 0 = 0
0 & 1 = 0
0 & 0 = 0
1 & 1 = 1

Converting these back to decimal 1001 is 9 and 0101 is 5. So 9 & 5 = 8. If we convert each of these bits to represent a role in our system, we can come up with a table like this.

Bit 1 0 (false) Student
Bit 2 0 (false) Graduate
Bit 3 0 (false) Staff
Bit 4 1 (true) Admin

So a user of the system with a role number of 8 is an Admin, but in our case, an Admin is also a member of staff, and in fact, a member of staff could also be a student or a graduate. This is where using bitwise operations can really help model such a situation. To get it working, a staff member who is a student will have bits 1 and 3 set to true, while a graduate who is also a staff member will have bits 2 and 3 set to true. We can represent these roles in decimal as User(Staff & Graduate) = 6, while User (Staff & Student) = 5. Get the picture?

Let’s look at a simple real world example. First we have a User class, with a Role property of the type int. The reason we use an integer, is that is can be easily stored in the database.

    1     public class User {

    2 

    3         public string Name { get; set; }

    4         public int Role { get; set; }

    5         public bool IsInRole(Role role) {

    6             //todo

    7             return false;

    8         }

    9     }

We also need to create an enumeration, with a Flags attribute. The flags attribute tells the compiler that this enumeration can be treated as a bit field. We then define a value for each role. The reason for using exponents of 2 should become clearer later.

    1     [Flags]

    2     public enum Role {

    3         Student = 1,    // 0001

    4         Employer = 2,   // 0010

    5         Staff = 4,      // 0100

    6         Admin = 8       // 1000

    7     }

The menu of our website needs to be generated depending on the user role. The menu selection code below should generate the correct menu depending on the user role.

    1     <div class="LeftMenu"> 

    2 

    3         <% if (user.IsInRole(Role.Student)) %>

    4             <% Html.RenderPartial("StudentMenu"); %>

    5 

    6         <% if (user.IsInRole(Role.Graduate)) %>

    7             <% Html.RenderPartial("GraduateMenu"); %>

    8 

    9         <% if (user.IsInRole(Role.Staff)) %>

   10             <% Html.RenderPartial("StaffMenu"); %>

   11 

   12         <% if (user.IsInRole(Role.Admin)) %>

   13             <% Html.RenderPartial("AdminMenu"); %>

   14 

   15     </div>

Ok, so let see where the magic happens! If we AND (&) the user assigned role, with the role required, and we compare this result to the role required, we can determine if a user is in the role. Summarised, the end result of the AND operation needs to equal that of the role required. In user class we have the method:

    1         public bool IsInRole(Role role) {

    2             Role userRole = (Role)this.Role;

    3             return ((userRole & role) == role);

    4         }

Looking at some binary examples, we can see how it works. In the first example, an admin user wants accesses a graduate item.

Role Required Staff(4) 0 1 0 0
User Role Admin (8) 1 0 0 0
Result of & Access Denied (0) 0 0 0 0

It is clear that we have a problem here, because we said that admin could be both staff, and staff may also be graduates. What we need to do is add up the roles, so that this user will access both admin and staff content. Assigning the user the role of Admin and Staff is easy. All we do is:

    1             User user = new User();

    2             user.Role = (int)Role.Staff;

    3             user.Role |= (int) Role.Admin;

And the resulting table is:

Role Required Staff(4) 0 1 0 0
User Role Admin + Staff (12) 1 1 0 0
Result of & Access Granted (4) 0 1 0 0

Now we can easily draw our menu depending on the roles assigned to a user. Adding or removing roles for a user is also easy, just add it or subtract it. I wrote a little project to go with this so you can test it our your self. Thanks to Michi for introducing this, and Dan for helping work it out!

Download the Roles sample project You’ll need to use nUnit to test it.

5 comments on “Role Based Access Control in MVC

  1. Simply and super!

    Thx

  2. Ah, the good old days were bit and byte operations are size and speed optimal: only need one byte to have 8 or even 16 roles (16-bits systems, they were the bomb!).

    However, there is one terrible flaw in your method. When a user is a student (1) and is assigned the role twice, it will add up to 2. Now he has employer rights! (The dream of each student that needs higher grades).

    You can make this fail safe with one simple alteration of your code. Don’t add up the roles with +=, but bitwise OR the roles with the | sign.

    • Thanks Bas, Made the changes to using the bitwise or operation.

  3. Converting these back to decimal 1001 is 9 and 0101 is 5. So 9 & 5 = 8?
    Right is 9 & 5 = 1

    • Not sure what you mean here Khoa? How does 9 & 5 = 8?