Quick and dirty role management in ASP.NET MVC
Wrapper around standard Membership provider that ships with ASP.NET MVC 1.0 out of the box fit well common scenario for social websites with self-registration and all users treated equal. When you have more complex requirements, in portal-like style application, you are very much out of luck. Account controller that comes with MVC 1.0 has very limited user management implementation and does not go into role management at all. It would be nice to have role management implemented the same way as account management, but if you need to roll right away I’ll show you quick and dirty way of doing basic user/role management with what we have now.
First, create new ASP.NET MVC project, I resourcefully call mine “MyPortal”, accepting all defaults. Then go to site configuration manager and create “Admin” user and two roles, “Users” and “Admins”. Assign Admin role of Admins. If you have issues using configuration manager, here is good tutorial.
With this basic setup taken care of, let’s take a look around to see what we got already. Along with two default views (home and about) we got log in and register screens to handle users.
What missing is ability to assign users to the roles. I’m ok with creating and deploying set of roles to the server using configuration manager, but handle each user this way is annoying at best. What I need is to be able to select role while creating new user. For the roles, I’ll add drop down box to the Register view:
<p>
<label for="roleName">Select Role:</label>
<%= Html.DropDownList("roleName") %>
<%= Html.ValidationMessage("roleName") %>
</p>
I’ll populate it in the AccountController, also setting Authorize attribute to only Admin access:
[Authorize(Roles = "Admins")]
public ActionResult Register()
{
ViewData["roleName"] = new SelectList(Roles.GetAllRoles(), "roleName");
ViewData["PasswordLength"] = MembershipService.MinPasswordLength;
return View();
}
And this is where it gets dirty. I’m throwing in the mix System.Web.Security.Roles – and it only exists within web context. That means, it will break unit test and defeat testability advantage that MVC has. Bad practice. You can wrap it up in the try/catch and suppress error to get all green test run. It won’t make it better practice, but getting greens back cheered me up a little bit.
To assign user role, I’ll again invoke dirty trick, this time using (OMG) Request.Forms:
if (createStatus == MembershipCreateStatus.Success)
{
Roles.AddUserToRole(userName, Request.Form["roleName"]);
FormsAuth.SignIn(userName, false /* createPersistentCookie */);
return RedirectToAction("Index", "Home");
}
I’ve also added “Register” tab to the menu bar and made it visible only for admins.
<%if (HttpContext.Current.User.IsInRole("Admins")) {%>
<li><%=Html.ActionLink("Register", "Register", "Account")%></li>
<%}%>
When this is done, I can log in as admin, go to Register tab and add user and select role for this user – exactly what I needed. Obviously, it is not a complete comprehensive solution by any means, but it serves my needs for now and hopefully will help you if you got into similar situation. Overtime role management need to have it’s own MVC-friendly implementation. But even with this limited functionality you can effectively manage new users, assign roles and secure your site with all kind of access rules your client will throw at you.
Source code for this project attached. Password for both Admin and User is “password”.