We often need to authenticate users and, depending on their roles, give them access to specific areas. MVC3 gives you a such possibility by means of RolesAdapter. But using RolesAdapter isn’t easy and you have to use ‘magic strings’ when using Authorize attribute. Let’s find other solution for solving this issue.
Replacement for RolesAdapter
First of all, we need to find a replacement for RolesAdapter and there is one written by Al-Farooque Shubho and can be downloaded from codeproject. All you need to do is download RoleBasedFormAuthentication.dll from codeproject and add it as a reference to your project. Then, instead of using FormsAuthentication class, use FormsAuthenticationUtil. It has “overloaded” methods SetAuthCookie and RedirectFromLoginPage which can take user roles (separated by comma) as an argument. The final step is to attach user roles when needed. We can do this on Application_AuthenticateRequest event in Global.asax file. Just invoke AttachRolesToUser method on FormsAuthorizationUtil class. More details can be found under the given URL.
Strongly typed User Roles
Now we can use Authorize attribute on our controller or action. But we still have to do this by giving the string, which contains user roles separated by comma. If we want to use strongly typed user roles, we have to replace Authorize attribute with our custom attribute.
[csharp]
public class UserRolesAuthorizeAttribute : AuthorizeAttribute
{
private UserRole[] _userRoles;
public UserRole[] UserRoles
{
set
{
_userRoles = value;
Roles = string.Join(",", value);
}
get { return _userRoles; }
}
}
[/csharp]
Now all we need to do is write UserRole enum and that’s it. Now our controller can look like this
[csharp]
public class RestrictedController : Controller
{
[UserRolesAuthorize(UserRoles = new[] { UserRole.Admin})]
public ActionResult Admin()
{
return View();
}
[UserRolesAuthorize(UserRoles = new[] { UserRole.Admin, UserRole.Moderator })]
public ActionResult Moderator()
{
return View();
}
[UserRolesAuthorize(UserRoles = new[] { UserRole.Admin, UserRole.Moderator, UserRole.User })]
public ActionResult UserArea()
{
return View();
}
}
[/csharp]
Keep in mind that enum name is used as a user role, so you have to make sure that roles assigned to a user have the same name as enum. You can download sample project using this technology to authorize user with a role.
This is solution I’ve used in my current project. We’ll be happy to hear your opinions and comments. Maybe somebody has a similar problem and solved it in a different way? Feel free to drop a line below.
Ok, but how you retrieve user roles in efficient way? Do you store them in session on cookie (if so do you store them in ciphered form)?
Your method strongly relies on enum, is there a way to be more DB reliable?
I rely on FormsAuthenticationUtil to store roles on client side which uses encrypted ticket from FormsAuthentication. You can check this on project’s site (http://www.codeproject.com/KB/web-security/RolesFormsAuthorization.aspx).
Some ORM enables mapping from tables (such user roles) to enum and this solves this problem. If not you can always map user role from db to enum manually.
I hope I’ve answered to your question. Thanks for asking.
I rely on FormsAuthenticationUtil to store roles on client side which uses encrypted ticket from FormsAuthentication. You can check this on project’s site (http://www.codeproject.com/KB/web-security/RolesFormsAuthorization.aspx).
Some ORM enables mapping from tables (such user roles) to enum and this solves this problem. If not you can always map user role from db to enum manually.
I hope I’ve answered to your question. Thanks for asking.