Asp.Net Forms Authentication with Groups and Roles

I found this great post from Rob Convery on creating a FilterAttribute that can be used to authorize specific controller actions against roles. I’d always wanted to implement a Group strategy and had made several attempts. They all seemed like kluges and I was never really happy.

One small change to Rob’s code and I can do grouping in a simple manner. Note: If you have a large number of roles and groups, this will probably not work for you. Also, this uses Asp.Net MVC.

ok, Rob’s code basically checked for a single role and you could use a constant to supply the role name. Something like

[RequiresRoleAttribute(RoleToCheckFor = ApplicationRoles.AdminRole)]
public ActionResult Edit(int id)

My change just allows you to pass more than one role into RoleToCheckFor.  Basically, I split RoleToCheckFor using a comma.

[RequiresRoleAttribute(RoleToCheckFor = ApplicationRoles.ChangeClientsGroup)]
public ActionResult Edit(int id)
The ApplicationRoles class looks like this.
public class ApplicationRoles
{
public const string AdminRole = "Admin";
public const string EntryRole = "Entry";
public const string ManagementRole = "Management";
public const string SecurityRole = "Security";

public const string ChangeClientsGroup = Admin + "," + Entry;
}

ChangeClientsGroup is simply a constant that contains all the allowed roles for changing clients. Biggest drawback here, I want to change a group, I need to redeploy. This isn’t really a problem since I don’t have to change my roles a lot but…
public class RequiresRoleAttribute : ActionFilterAttribute
{
public string RoleToCheckFor { get; set; }

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//redirect if the user is not authenticated
if (!String.IsNullOrEmpty(RoleToCheckFor))
{

if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{

//use the current url for the redirect
string redirectOnSuccess = filterContext.HttpContext.Request.Url.AbsolutePath;

//send them off to the login page
string redirectUrl = string.Format("?ReturnUrl={0}", redirectOnSuccess);
string loginUrl = FormsAuthentication.LoginUrl + redirectUrl;
filterContext.HttpContext.Response.Redirect(loginUrl, true);

}
else
{
bool isAuthorized = false;
string[] roles = this.RoleToCheckFor.Replace(" ", string.Empty).Split(',');
foreach (string role in roles)
{
isAuthorized = filterContext.HttpContext.User.IsInRole(role);
if (isAuthorized) { break; }
}
if (!isAuthorized)
{
ApplicationError appEevent = new ApplicationError();
appEevent.Caller = Thread.CurrentPrincipal.Identity.Name + ":" + filterContext.Controller.GetType().Name + ":" + filterContext.HttpContext.Request.Path;
appEevent.ErrorMessage = "Unauthorized access attempt";
ApplicationManager.RecordEvent(appEevent);
FormsAuthentication.SignOut();
filterContext.HttpContext.Response.Redirect("/SecurityViolation.htm", true);
}
}
}
else
{
throw new InvalidOperationException("No Role Specified");
}
}
}

Hopes this works for you!

Comments

Popular posts from this blog

Migrating Legacy Apps to the New SimpleMembership Provider

Get Asp.Net Profile properties from Sql

JavaScript function to automatically add slashes to date