Non-string role names in ASP.NET MVC? - asp.net-mvc

ASP.NET MVC has good support for role-based security, but the usage of strings as role names is maddening, simply because they cannot be strongly-typed as enumerations.
For example, I have an "Admin" role in my app. The "Admin" string will now exist in the Authorize attribute of my action, in my master page (for hiding a tab), in my database (for defining the roles available to each user), and any other place in my code or view files where I need to perform special logic for admin or non-admin users.
Is there a better solution, short of writing my own authorization attribute and filter, that would perhaps deal with a collection of enumeration values?

Using magic strings gives you the flexibility to declare multiple roles in the Authorize attribute (e.g. [Authorize(Roles = "Admin, Moderator")] which you tend to lose as you go to a strongly typed solution. But here's how you can maintain this flexibility while still getting everything strongly typed.
Define your roles in an enum that uses bit flags:
[Flags]
public enum AppRole {
Admin = 1,
Moderator = 2,
Editor = 4,
Contributor = 8,
User = 16
}
Override AuthorizeAttribute:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class MyAuthorizeAttribute : AuthorizeAttribute {
public AppRole AppRole { get; set; }
public override void OnAuthorization(AuthorizationContext filterContext) {
if (AppRole != 0)
Roles = AppRole.ToString();
base.OnAuthorization(filterContext);
}
}
Now if you can use MyAuthorizeAttribute like this:
[MyAuthorize(AppRole = AppRole.Admin | AppRole.Moderator | AppRole.Editor)]
public ActionResult Index() {
return View();
}
The above action will only authorize users that are in at least one of the roles listed (Admin, Moderator, or Editor). The behavior is the same as MVC's default AuthorizeAttribute, except without the magic strings.
If you use this technique, here's an extension method on IPrincipal that may also be useful:
public static class PrincipalExtensions {
public static bool IsInRole(this IPrincipal user, AppRole appRole) {
var roles = appRole.ToString().Split(',').Select(x => x.Trim());
foreach (var role in roles) {
if (user.IsInRole(role))
return true;
}
return false;
}
}
You can use this extension method like this:
public ActionResult Index() {
var allowed = User.IsInRole(AppRole.Admin | AppRole.Moderator | AppRole.Editor);
if (!allowed) {
// Do Something
}
return View();
}

I usually use a class with a bunch of string constants. It's not a perfect solution, since you need to remember to stick to using it everywhere, but at least it gets rid of the possibility of typos.
static class Role {
public const string Admin = "Admin";
}

Although it doesn't use enums, I've used the solution below, where we sub-class the Authorize filter to take in variable length role name arguments in the constructor. Using this together with role names declared in const variables somewhere, we avoid magic strings:
public class AuthorizeRolesAttribute : AuthorizeAttribute
{
public AuthorizeRolesAttribute(params string[] roles) : base()
{
Roles = string.Join(",", roles);
}
}
public class MyController : Controller
{
private const string AdministratorRole = "Administrator";
private const string AssistantRole = "Assistant";
[AuthorizeRoles(AdministratorRole, AssistantRole)]
public ActionResult AdminOrAssistant()
{
return View();
}
}
(I blogged about this in a little bit more detail - http://tech-journals.com/jonow/2011/05/19/avoiding-magic-strings-in-asp-net-mvc-authorize-filters)

I took JohnnyO's response but changed the enumeration items to use the DescriptionAttribute to specify the string value for the role. This comes in handy if you want your role string to be different from the Enum name.
The enum example:
[Flags]
public enum AppRole
{
[Description("myRole_1")]
RoleOne = 1,
[Description("myRole_2")]
RoleTwo = 2
}
The extension method:
public static bool IsInRole(this IPrincipal user, AppRole appRole)
{
var roles = new List<string>();
foreach (var role in (AppRole[])Enum.GetValues(typeof(AppRole)))
if ((appRole & role) != 0)
roles.Add(role.ToDescription());
return roles.Any(user.IsInRole);
}
The custom attribute:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AppAuthorizeAttribute : AuthorizeAttribute
{
public AppRole AppRoles { get; set; }
public override void OnAuthorization(AuthorizationContext filterContext)
{
var roles = new List<string>();
foreach (var role in (AppRole[])Enum.GetValues(typeof(AppRole)))
if((AppRoles & role) != 0)
roles.Add(role.ToDescription());
if (roles.Count > 0)
Roles = string.Join(",", roles);
base.OnAuthorization(filterContext);
}
}
Extension method to get the description value:
public static string ToDescription(this Enum value)
{
var da = (DescriptionAttribute[])
(value.GetType().GetField(value.ToString()))
.GetCustomAttributes(typeof (DescriptionAttribute), false);
return da.Length > 0 ? da[0].Description : value.ToString();
}

It's not that hard to customize AuthorizeAttribute in the way you suggest.
Subtype it, add a custom property for your enum type, and call ToString() on the passed value. Put that in the regular roles property. This should take just a few lines of code, and AuthorizeAttribute still does all the real work.
+1 for Matti, too, since consts are also a good choice.

I have used a static class defining a bunch of string constants as suggested by Matti and on my current project I use the below extension method with an enum. Both approaches work very well.
public static class EnumerationExtension
{
public static string GetName(this Enum e)
{
return Enum.GetName(e.GetType(), e);
}
}

Related

Mvc Application, windows authentication, authorization, visibility

I have a windows authentication MVC app that needs the username to do a lookup to determine if links are visible and set authorization. Note: I do visibility/Authorization with roles as well.
I need the username so I am currently doing it in OnAuthentification (not sure if this is the right place). I am splicing the username down to put it on the main page and say welcome, User. (presentation purposes)
[Authorize]
public abstract class ApplicationController : Controller
{
public static bool IsApprover;
protected override void OnAuthentication(AuthenticationContext filterContext)
{
base.OnAuthentication(filterContext);
if (filterContext.RequestContext.HttpContext.User.Identity.IsAuthenticated == true)
{
string userName = User.Identity.Name.Remove(0, 16).Replace('.', ' ').ToLower();
HttpContext.Application["UserName"] = TitleCase(userName, "Nothing");
//Initialize Values
HttpContext.Application["IsApprover"] = false; //used for link visibility
IsApprover = false; //used for Authorization
//do db lookup and set IsApprover values
}
}
}
So, I set the values above. I am not including the entity framework code just to be brief. The above works fine and every controller inherits from ApplicationController.
I also have
public class CustomAuthorizationValue : AuthorizeAttribute
{
private bool localIsAllowed;
public CustomAuthorizationValue(bool isAllowed)
{
localIsAllowed = isAllowed;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext.Request.IsLocal)
{
var authorized = base.AuthorizeCore(httpContext);
if (!authorized)
{
// The user is not authorized => no need to go any further
return false;
}
return localIsAllowed;
}
return false;
}
}
For Authorization I use:
[CustomAuthorizationValue(IsApprover)]
public ActionResult Approve()
{
//code
}
For Visibility in Razor I use
#if((bool)#HttpContext.Current.Application["IsApprover"] == true)
{
<li>Approve (#HttpContext.Current.Application["ApproveCount"])</li>
}
This works fine but I have 2 different variables to use,
one for visibility (HttpContext.Current.Application["IsApprover"])
and
one for Authorization (IsApprover).
Is there a more elegant solution?
Is there another place to put the code rather than override void OnAuthentication?
Is there a way I can just set 1 variable for visibility and Authorization rather than having 2?
Is this the best practice or am I way off?
The above works fine and every controller inherits from
ApplicationController.
Hmmmm. You are storing user specific information information in the wrong scope:
HttpContext.Application["UserName"] = TitleCase(userName, "Nothing");
HttpContext.Application["IsApprover"] = false;
In ASP.NET, the Application scope is shared among ALL users of your website. So you have a concurrency issue here.
You should use the HTTP Context scope instead:
HttpContext.Items["UserName"] = TitleCase(userName, "Nothing");
HttpContext.Items["IsApprover"] = false;
Is there a more elegant solution?
You could use a view model:
public class MyViewModel
{
public string UserName { get; set; }
public bool IsApprover { get; set; }
}
and then have a couple of extension methods to work more easily:
public static class HttpContextExtensions
{
private const string MyViewModelKey = "__MyViewModel__";
public static MyViewModel GetMyViewModel(this HttpContextBase context)
{
return (MyViewModel)context.Items[MyViewModelKey];
}
public static void SetMyViewModel(this HttpContextBase context, MyViewModel model)
{
context.Items[MyViewModelKey] = model;
}
}
and then use those extension methods:
if (filterContext.RequestContext.HttpContext.User.Identity.IsAuthenticated)
{
string userName = User.Identity.Name.Remove(0, 16).Replace('.', ' ').ToLower();
bool isApprover = ... do db lookup and set IsApprover value
var model = new MyViewModel
{
UserName = TitleCase(userName, "Nothing"),
IsApprover = isApprover,
}
this.HttpContext.SetMyViewModel(model);
}
and in your view:
#if(HttpContext.GetMyViewModel().IsApprover)
{
<li>
<a href="#Url.Action("Approve", "Approve")">
Approve (#HttpContext.Current.Application["ApproveCount"])
</a>
</li>
}
NOTE: In this anchor text once again you seem to be using the Application scope to store user specific information such as ApproveCount which we discussed earlier.
Is this the best practice or am I way off?
Well, I would probably use claims based authentication and store this information (IsApprover, ...) as claims in the current user.

How to authorize request using Task based model

We are designing application using MVC. We have thousands of user and more than 100 roles. Tasks (access rights for specific action )are assigned to roles.
There are many tasks assigned to multiple roles meaning that task can be shared among roles. Due to nature of application we have to add/delete/update roles and therefore we can not use role based authorization.
Need help to advise on how to implement task based authorization where application does not bother about roles.
Thanks.
You can use bit flag enums to create list of tasks and assign user permission using them. Unfortunately, even if you use ulong, this will limit you with maximum 64 options. Here is a sample code:
[Flags]
public enum TaskPermissions : ulong
{
None = 0x0000,
CanDoTask1 = 0x0001,
CanDoTask2 = 0x0002,
CanDoTask3 = 0x0004,
CanDoTask4 = 0x0008,
CanDoTask5 = 0x0010,
// ... powers of 2
CanDoEverything = 0xFFFF
}
public class Member
{
public string Username {get;set;}
public TaskPermissions Permissions { get; set; }
// other things that are necessary
public bool HasPermission(TaskPermissions permissions)
{
return (Permissions & permissions) == permissions;
}
}
To set permissions:
var member=new Member():
member.Permissions= TaskPermissions.CanDoTask1 | TaskPermissions.CanDoTask2;
To check a permission:
member.HasPermission(TaskPermissions.CanDoTask1);
Sample AuthorizationRequiredAttribute for Mvc (assuming member is in session):
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class AuthorizationRequiredAttribute : ActionFilterAttribute
{
public TaskPermissions RequiredPermissions { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.Controller.Session["Member"].HasPermission(RequiredPermissions))
{
base.OnActionExecuting(filterContext);
return;
}
throw new AuthenticationException("Access denied");
}
}
Usage:
[AuthorizationRequired(RequiredPermissions = TaskPermissions.CanDoTask1)]
public class TestController : Controller
{
//methods
}

ASP .NET MVC Securing a Controller/Action

If I want only administrator to access the action called "ManagerUser", I know I can do this:
[Authorize( Roles = Constants.ROLES_ADMINISTRATOR )]
public ActionResult ManageUser( string id )
{
}
What if I want to give everyone access except to administrator? I do not want to write all roles up there on function :|.
Any recommendations/way outs?
You can create your own custom Authorize attribute, something like "AuthorizeAllExceptAdmin." Within that class you would simply need to check whether or not the current user was an admin, and if they were reject it, otherwise accept it.
Here's a good tutorial, but you'll probably end up with something like:
public class AuthorizeAllExceptAdmin : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
return !httpContext.User.IsInRole(Constants.ROLES_ADMINISTRATOR);
}
}
Then your controller method becomes:
[AuthorizeAllExceptAdmin]
public ActionResult SomethingOnlyNonAdminsCanDo()
{
}
Here's an example of the custom attribute that takes in roles to deny.
public class DoNotAuthorize : AuthorizeAttribute
{
private IEnumerable<string> _rolesToReject;
public DoNotAuthorize(IEnumerable<string> rolesToReject)
{
_rolesToReject = rolesToReject;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
foreach (var role in _rolesToReject)
{
if (httpContext.User.IsInRole(role))
return false;
}
return true;
}
}
Then your controller method becomes:
[DoNotAuthorize(new [] {Constants.ROLES_ADMINISTRATOR})]
public ActionResult SomethingOnlyNonAdminsCanDo()
{
}
I would put some thought into it before choosing one of the above options. If you think you'll have several methods (or entire controllers) with similar authorization requirements (i.e, several actions an admin can not perform) then I would stick with the non-parameterized custom attribute. This way, you can evolve them all together (by only changing the custom attribute) later on. For example, maybe later on you want admins to be able to go into a special mode where they can perform these actions.
Alternatively, if the autorization is more varied amongst the actions, then using the parameterized list makes sense, since they'll evolve relatively independently.
Besides creating a custom AuthorizeAttribute, suggested by manu, you could use PrincipalPermission, with a Deny-SecurityAction:
[PrincipalPermission(SecurityAction.Deny, Role="Administrator")]
In my app I don't use roles so I have to query the database to determine whether the user has access or not. The benefits of the code below is that you can redirect the user to a certain action very easily. I explained the code in my blog post at http://blog.athe.la/2009/12/implementing-permission-via-windows-authentication-in-asp-mvc-using-action-filters/
public class DatabaseRepository()
{
private readonly DatabaseDataContext db = new DatabaseDataContext();
public bool UserHasPermission(string userLogon) {
return (from permission this.db.Permissions
where permission.HasPermissionSw == true
select permission).Contains(userLogon);
}
}
public class UserHasPermission: ActionFilterAttribute
{
private readonly DatabaseRepository databaseRepository = new DatabaseRepository();
private readonly string redirectAction;
public UserHasPermission(string redirectTo)
{
this.redirectAction = redirectTo;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
string userLogon = filterContext.HttpContext.User.Identity.Name;
if (!this.databaseRepository.UserHasPermission(userLogon))
{
string routeController = filterContext.Controller.ControllerContext.RouteData.Values["controller"];
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = routeController, action = this.redirectAction }));
}
}
}
Your controller would then look something like this:
[UserHasPermission("NoAccess")]
public ActionResult SecretArea()
{
// run all the logic
return View();
}
public ActionResult NoAccess()
{
return View();
}

Authorize Attribute, filter by Roles AND just one other userID

How can I include a user regardless of his role, dependent on a matching userID, and not always same user:
[Authorize(Roles="Group1") AND userID=uniqueID]
You won't be able to do this with the default AuthorizeAttribute. You will need to extend AuthorizeAttribute with a custom class that adds the user behavior. Typically it uses named users, but you could provide an alternative. Normally if you supply both Users and Roles, it will require that the user be in the list of users and have one of the indicated roles.
public class UserOrRoleAuthorizeAttribute : AuthorizeAttribute
{
public int? SuperUserID { get; set; }
protected override bool AuthorizeCore( HttpContextBase httpContext )
{
if (base.AuthorizeCore( httpContext ))
{
var userid == ...get id of current user from db...
return userid == this.SuperUserID;
}
return false;
}
}
Used as:
[UserOrRoleAuthorize(Roles="Admin",SuperUserID=15)]
public ActionResult SomeAction() ...
Note that you could also add in some way of specifing where to look for the id for this action, .i.e.,
Table="Admins",Column="AdminID",MatchProperty="Company",MatchParameter="company"
then put some code into the attribute to look up the value in the property table and column and comparing it to the specified RouteValue entry instead of hard-coding it.
You could write a custom Authorize filter (implement IAuthorizationFilter)
Your custom Authorize filter could take the userId as a parameter.
Something like
public class
YourAuthorizeFilterAttribute : AuthorizeAttribute, IAuthorizationFilter
{
public string UserId { get; set; }
public void OnAuthorization(AuthorizationContext filterContext)
{
if(filterContext.HttpContext.User.Identity.Name != UserId &&
!filterContext.HttpContext.User.IsInRole(base.Roles))
{
filterContext.Result = new RedirectResult("/Account/LogOn");
}
}
}
Then use your own filter like so
[YourAuthorizeFilter(UserId = "theuser", Roles ="Group1")]
Kindness,
Dan

asp.net mvc decorate [Authorize()] with multiple enums

I have a controller and I want two roles to be able to access it. 1-admin OR 2-moderator
I know you can do [Authorize(Roles="admin, moderators")] but I have my roles in an enum. With the enum I can only authorize ONE role. I can't figure out how to authorize two.
I have tried something like [Authorize(Roles=MyEnum.Admin, MyEnum.Moderator)] but that wont compile.
Someone once suggested this:
[Authorize(Roles=MyEnum.Admin)]
[Authorize(MyEnum.Moderator)]
public ActionResult myAction()
{
}
but it doesn't work as an OR. I think in this case the user has to be part of BOTH roles. Am I overlooking some syntax? Or is this a case where I have to roll my own custom authorization?
Here is a simple and elegant solution which allows you to simply use the following syntax:
[AuthorizeRoles(MyEnum.Admin, MyEnum.Moderator)]
When creating your own attribute, use the params keyword in your constructor:
public class AuthorizeRoles : AuthorizeAttribute
{
public AuthorizeRoles(params MyEnum[] roles)
{
...
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
...
}
}
This will allow you to use the attribute as follows:
[AuthorizeRoles(MyEnum.Admin, MyEnum.Moderator)]
public ActionResult myAction()
{
}
Try using the bit OR operator like this:
[Authorize(Roles= MyEnum.Admin | MyEnum.Moderator)]
public ActionResult myAction()
{
}
If that doesn't work, you could just roll your own. I currently just did this on my project. Here's what I did:
public class AuthWhereRole : AuthorizeAttribute
{
/// <summary>
/// Add the allowed roles to this property.
/// </summary>
public UserRole Is;
/// <summary>
/// Checks to see if the user is authenticated and has the
/// correct role to access a particular view.
/// </summary>
/// <param name="httpContext"></param>
/// <returns></returns>
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext == null)
throw new ArgumentNullException("httpContext");
// Make sure the user is authenticated.
if (!httpContext.User.Identity.IsAuthenticated)
return false;
UserRole role = someUser.Role; // Load the user's role here
// Perform a bitwise operation to see if the user's role
// is in the passed in role values.
if (Is != 0 && ((Is & role) != role))
return false;
return true;
}
}
// Example Use
[AuthWhereRole(Is=MyEnum.Admin|MyEnum.Newbie)]
public ActionResult Test() {}
Also, make sure to add a flags attribute to your enum and make sure they are all valued from 1 and up. Like this:
[Flags]
public enum Roles
{
Admin = 1,
Moderator = 1 << 1,
Newbie = 1 << 2
etc...
}
The left bit shifting gives the values 1, 2, 4, 8, 16 and so on.
Well, I hope this helps a little.
I combined a few of the solutions here to create my personal favorite. My custom attribute just changes the data to be in the form that SimpleMembership expects and lets it handle everything else.
My roles enum:
public enum MyRoles
{
Admin,
User,
}
To create roles:
public static void CreateDefaultRoles()
{
foreach (var role in Enum.GetNames(typeof(MyRoles)))
{
if (!Roles.RoleExists(role))
{
Roles.CreateRole(role);
}
}
}
Custom attribute:
public class AuthorizeRolesAttribute : AuthorizeAttribute
{
public AuthorizeRolesAttribute(params MyRoles[] allowedRoles)
{
var allowedRolesAsStrings = allowedRoles.Select(x => Enum.GetName(typeof(MyRoles), x));
Roles = string.Join(",", allowedRolesAsStrings);
}
}
Used like so:
[AuthorizeRoles(MyRoles.Admin, MyRoles.User)]
public ActionResult MyAction()
{
return View();
}
Try
public class CustomAuthorize : AuthorizeAttribute
{
public enum Role
{
DomainName_My_Group_Name,
DomainName_My_Other_Group_Name
}
public CustomAuthorize(params Role[] DomainRoles)
{
foreach (var domainRole in DomainRoles)
{
var domain = domainRole.ToString().Split('_')[0] + "_";
var role = domainRole.ToString().Replace(domain, "").Replace("_", " ");
domain=domain.Replace("_", "\\");
Roles += ", " + domain + role;
}
Roles = Roles.Substring(2);
}
}
public class HomeController : Controller
{
[CustomAuthorize(Role.DomainName_My_Group_Name, Role.DomainName_My_Other_Group_Name)]
public ActionResult Index()
{
return View();
}
}
Here's my version, based on #CalebHC and #Lee Harold's answers.
I've followed the style of using named parameters in the attribute and overridden the base classes Roles property.
#CalebHC's answer uses a new Is property which I think is unnecessary, because AuthorizeCore() is overridden (which in the base class uses Roles) so it makes sense to use our own Roles as well. By using our own Roles we get to write Roles = Roles.Admin on the controller, which follows the style of other .Net attributes.
I've used two constructors to CustomAuthorizeAttribute to show real active directory group names being passed in. In production I use the parameterised constructor to avoid magic strings in the class: group names are pulled from web.config during Application_Start() and passed in on creation using a DI tool.
You'll need a NotAuthorized.cshtml or similar in your Views\Shared folder or unauthorized users will get an error screen.
Here is the code for the base class AuthorizationAttribute.cs.
Controller:
public ActionResult Index()
{
return this.View();
}
[CustomAuthorize(Roles = Roles.Admin)]
public ActionResult About()
{
return this.View();
}
CustomAuthorizeAttribute:
// The left bit shifting gives the values 1, 2, 4, 8, 16 and so on.
[Flags]
public enum Roles
{
Admin = 1,
User = 1 << 1
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
private readonly string adminGroupName;
private readonly string userGroupName;
public CustomAuthorizeAttribute() : this("Domain Admins", "Domain Users")
{
}
private CustomAuthorizeAttribute(string adminGroupName, string userGroupName)
{
this.adminGroupName = adminGroupName;
this.userGroupName = userGroupName;
}
/// <summary>
/// Gets or sets the allowed roles.
/// </summary>
public new Roles Roles { get; set; }
/// <summary>
/// Checks to see if the user is authenticated and has the
/// correct role to access a particular view.
/// </summary>
/// <param name="httpContext">The HTTP context.</param>
/// <returns>[True] if the user is authenticated and has the correct role</returns>
/// <remarks>
/// This method must be thread-safe since it is called by the thread-safe OnCacheAuthorization() method.
/// </remarks>
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext == null)
{
throw new ArgumentNullException("httpContext");
}
if (!httpContext.User.Identity.IsAuthenticated)
{
return false;
}
var usersRoles = this.GetUsersRoles(httpContext.User);
return this.Roles == 0 || usersRoles.Any(role => (this.Roles & role) == role);
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
filterContext.Result = new ViewResult { ViewName = "NotAuthorized" };
}
private IEnumerable<Roles> GetUsersRoles(IPrincipal principal)
{
var roles = new List<Roles>();
if (principal.IsInRole(this.adminGroupName))
{
roles.Add(Roles.Admin);
}
if (principal.IsInRole(this.userGroupName))
{
roles.Add(Roles.User);
}
return roles;
}
}
To add to CalebHC's code and answer ssmith's question about handling users who have multiple roles...
Our custom security principal returns a string array representing all the groups/roles that a user is in. So first we have to convert all the strings in the array that match items in the enum. Finally, we look for any match - if so, then the user is authorized.
Note that we're also redirecting an unauthorized user to a custom "NotAuthorized" view.
The whole class looks like this:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
/// <summary>
/// Add the allowed roles to this property.
/// </summary>
public Roles Is { get; set; }
/// <summary>
/// Checks to see if the user is authenticated and has the
/// correct role to access a particular view.
/// </summary>
/// <param name="httpContext"></param>
/// <returns></returns>
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext == null)
throw new ArgumentNullException("httpContext");
if (!httpContext.User.Identity.IsAuthenticated)
return false;
var iCustomPrincipal = (ICustomPrincipal) httpContext.User;
var roles = iCustomPrincipal.CustomIdentity
.GetGroups()
.Select(s => Enum.Parse(typeof (Roles), s))
.ToArray();
if (Is != 0 && !roles.Cast<Roles>().Any(role => ((Is & role) == role)))
{
return false;
}
return true;
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext == null)
throw new ArgumentNullException("filterContext");
filterContext.Result = new ViewResult { ViewName = "NotAuthorized" };
}
}
Or you could concatenate like:
[Authorize(Roles = Common.Lookup.Item.SecurityRole.Administrator + "," + Common.Lookup.Item.SecurityRole.Intake)]

Resources