325

Right now I decorate a method like this to allow "members" to access my controller action

[Authorize(Roles="members")]

How do I allow more than one role? For example the following does not work but it shows what I am trying to do (allow "members" and "admin" access):

[Authorize(Roles="members", "admin")] 
Pablo Claus
  • 5,886
  • 3
  • 29
  • 38
codette
  • 12,343
  • 9
  • 37
  • 38
  • 4
    Please change the accepted answer to this question. The person with the currently accepted answer edited it indicating that he was wrong. – Eric J. Mar 28 '14 at 20:14

13 Answers13

676

Another option is to use a single authorize filter as you posted but remove the inner quotations.

[Authorize(Roles="members,admin")]
Sonhja
  • 8,230
  • 20
  • 73
  • 131
Jim Schmehil
  • 6,881
  • 2
  • 15
  • 6
  • 5
    Works in MVC 5 too. +1 – gkonuralp Jul 24 '15 at 06:25
  • 5
    Works in ASP.NET Core 1.0 (MVC 6) and Microsoft.AspNet.Identity v3.* – Søren Jun 21 '16 at 08:19
  • 4
    This is okay if you only have one controller that you need to authorize. If you have more than one, you're duplicating those string constants (yuck). I much prefer the static class that has the role names. My pet hate is duplicate strings... so so bad. – robnick Aug 17 '18 at 00:55
  • For the life of me I cannot get this to work. It's fine if I specify [Authorize(Roles = "Administrator")], but not if I specify [Authorize(Roles = "Administrator, PowerUser")]. I'm using MVC v5.2.7 – Craig May 30 '19 at 03:46
  • So now I'm testing a custom attribute inheriting from AuthorizeAttribute. It's okay with just Administrator, it hits my break point in HandleUnauthorizedRequest just fine, but if I specify Administrator and PowerUser, it doesn't hit the break point at all and access is granted to the action. What the?!? – Craig May 30 '19 at 04:00
  • Never mind. I think it's a cookies issue. My user still appears to be logged in. – Craig May 30 '19 at 04:18
  • 1
    @kraeg good news that you solved your problem. Now, consider deleting your comments, please – Pablo Claus Jun 18 '19 at 17:38
  • 2
    Why? It took me ages to work this out. It may be helpful for someone else experiencing the same problem. – Craig Jun 21 '19 at 03:30
  • Why? Because it is very long, SO cuts it, and nobody reads completely when seeing the answer. At best it could condense everything into a single brief comment. – Pablo Claus Jun 24 '19 at 13:35
  • 1
    Only to add some more info on this issue... This answer is not completely correct. If you go to the Roles Authorization assign, it does this split: original.Split(',')) So if you have any spaces on the Roles name, it won't work!! Be careful with that. Just use the same solution as @Jim Schmehil suggests, but with no spaces on your role names – Sonhja Jan 03 '20 at 15:03
  • 3
    extra note: as per https://learn.microsoft.com/en-us/aspnet/core/security/authorization/roles?view=aspnetcore-6.0#adding-role-checks - this is `OR` and not `AND` – gawkface Mar 01 '22 at 01:14
161

If you want use custom roles, you can do this:

CustomRoles class:

public static class CustomRoles
{
    public const string Administrator = "Administrador";
    public const string User = "Usuario";
}

Usage

[Authorize(Roles = CustomRoles.Administrator +","+ CustomRoles.User)]

If you have few roles, maybe you can combine them (for clarity) like this:

public static class CustomRoles
{
     public const string Administrator = "Administrador";
     public const string User = "Usuario";
     public const string AdministratorOrUser = Administrator + "," + User;  
}

Usage

[Authorize(Roles = CustomRoles.AdministratorOrUser)]
Pablo Claus
  • 5,886
  • 3
  • 29
  • 38
  • 9
    This would be a good answer, if you explained to people who didn't know what's behind CustomRoles. – James Skemp Jun 15 '12 at 01:39
  • 1
    @JamesSkemp ok, i've extended my answer. It is very simple. CustumRoles is a class that i created that contains some constants, that corresponds with my application roles. I did that for a few reasons: 1) It allow the use of intellisense to avoid spelling mistakes 2)To simplify maintenance. If a role change, i have to update only one place within my application. – Pablo Claus Jun 15 '12 at 11:32
  • @Pabloker Alternatively you can create an enum with an Flags attribute, e.g. Convert.ToString(CustomRoles.Administrator | CustomRoles.User); - annoying part is that this requires an explicit conversion – cstruter Sep 14 '12 at 09:41
  • If you have 39 roles ? – Kiquenet Nov 14 '18 at 11:12
  • I think your problem goes through the modeling of permits beyond what can be done with .net – Pablo Claus Nov 14 '18 at 13:41
105

One possible simplification would be to subclass AuthorizeAttribute:

public class RolesAttribute : AuthorizeAttribute
{
    public RolesAttribute(params string[] roles)
    {
        Roles = String.Join(",", roles);
    }
}

Usage:

[Roles("members", "admin")]

Semantically it is the same as Jim Schmehil's answer.

Mihkel Müür
  • 2,162
  • 1
  • 20
  • 15
  • 4
    This does not worked for me, the logged in user was able to bypass the attribute even if the user did not have any of the roles. – Urielzen Mar 07 '16 at 07:20
  • 13
    This answer is better for when you are using constants as your values: ie [Roles(Constants.Admin,Constants.Owner)] – dalcam Jun 23 '16 at 17:07
  • 5
    this is the best answer – IgorShch Aug 16 '18 at 12:22
  • 4
    I know this is an old post, but let me add this. In order for this code snippet to work, you have to use `System.Web.Mvc.AuthorizeAttribute` for `System.Web.Mvc.Controllers` and `System.Web.Http.AuthorizeAttribute` for `System.Web.Http.ApiController` (RESTful calls). – Efthymios Oct 08 '20 at 10:32
19

For MVC4, using a Enum (UserRoles) with my roles, I use a custom AuthorizeAttribute.

On my controlled action, I do:

[CustomAuthorize(UserRoles.Admin, UserRoles.User)]
public ActionResult ChangePassword()
{
    return View();
}

And I use a custom AuthorizeAttribute like that:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class CustomAuthorize : AuthorizeAttribute
{
    private string[] UserProfilesRequired { get; set; }

    public CustomAuthorize(params object[] userProfilesRequired)
    {
        if (userProfilesRequired.Any(p => p.GetType().BaseType != typeof(Enum)))
            throw new ArgumentException("userProfilesRequired");

        this.UserProfilesRequired = userProfilesRequired.Select(p => Enum.GetName(p.GetType(), p)).ToArray();
    }

    public override void OnAuthorization(AuthorizationContext context)
    {
        bool authorized = false;

        foreach (var role in this.UserProfilesRequired)
            if (HttpContext.Current.User.IsInRole(role))
            {
                authorized = true;
                break;
            }

        if (!authorized)
        {
            var url = new UrlHelper(context.RequestContext);
            var logonUrl = url.Action("Http", "Error", new { Id = 401, Area = "" });
            context.Result = new RedirectResult(logonUrl);

            return;
        }
    }
}

This is part of modifed FNHMVC by Fabricio Martínez Tamayo https://github.com/fabriciomrtnz/FNHMVC/

  • 1
    Your OnAuthorization method will require the user to have **all** the enumerated roles; was that intentional, or are you missing a break in that loop? – Tieson T. Jan 05 '15 at 05:18
  • @Tieson: I inspected that pretty closely, it definitely seems like a break would be required in that loop. – OcelotXL Jan 21 '15 at 02:26
  • @TiesonT. and @ madrush, I appreciate your fix, it really could have a break inside the loop. I'll change the code above. – Bernardo Loureiro Jan 26 '15 at 13:19
  • The enum *UserRoles* is nice. Do you declare it manually or is it autogenerated based on the contents of the DB? – Konrad Viltersten Jan 03 '16 at 12:12
  • @KonradViltersten It's manually but I guess with Reflection and Dynamic class autogenerated can be done – Bernardo Loureiro Jan 03 '16 at 21:58
  • Overriding OnAuthorization is a bad idea. There is some code which protects against cached pages being served up in the original. Check the source. – Worthy7 Jun 20 '16 at 06:57
10

You can use Authorization Policy in Startup.cs

    services.AddAuthorization(options =>
    {
        options.AddPolicy("admin", policy => policy.RequireRole("SuperAdmin","Admin"));
        options.AddPolicy("teacher", policy => policy.RequireRole("SuperAdmin", "Admin", "Teacher"));
    });

And in Controller Files:

 [Authorize(Policy = "teacher")]
 [HttpGet("stats/{id}")]
 public async Task<IActionResult> getStudentStats(int id)
 { ... }

"teacher" policy accept 3 roles.

Sedat Y
  • 561
  • 5
  • 6
4

Another clear solution, you can use constants to keep convention and add multiple [Authorize] attributes. Check this out:

public static class RolesConvention
{
    public const string Administrator = "Administrator";
    public const string Guest = "Guest";
}

Then in the controller:

[Authorize(Roles = RolesConvention.Administrator )]
[Authorize(Roles = RolesConvention.Guest)]
[Produces("application/json")]
[Route("api/[controller]")]
public class MyController : Controller
  • 23
    Multiple `Authorize` attributes employ AND semantics and require ALL conditions to be met (i.e. user has to be in both the Administrator and Guest roles). – trousyt Mar 17 '17 at 20:44
4

Using AspNetCore 2.x, you have to go a little different way:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class AuthorizeRoleAttribute : AuthorizeAttribute
{
    public AuthorizeRoleAttribute(params YourEnum[] roles)
    {
        Policy = string.Join(",", roles.Select(r => r.GetDescription()));
    }
}

just use it like this:

[Authorize(YourEnum.Role1, YourEnum.Role2)]
DirtyNative
  • 2,553
  • 2
  • 33
  • 58
4

I mixed answers and proposed this method.

Firstly, We create an enum for role accesses.

public enum ERoleAccess
{
     [Description("Admin User")]
     Admin = 1,

     [Description("General User")]
     User = 2,

     [Description("Editor User")]
     Editor = 3,
}

Secondly, we need an attribute filter for customer MVC authorize.

public class RolesAttribute:AuthorizeAttribute
{
   public RolesAttribute(params ERoleAccess[] roles)
   {
      Roles = string.Join(",", roles);
   }
}

Finally, we can use "RolesAttribute" on the controllers or actions.


[Roles(ERoleAccess.Admin, ERoleAccess.Editor, ERoleAccess.User)]

In this approach, we use numbers of alternative string values. (1= Admin, 2=User,...)

It's good for decreasing token size and comparing performance.

Pablo Claus
  • 5,886
  • 3
  • 29
  • 38
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Oct 06 '22 at 00:31
3

Better code with adding a subclass AuthorizeRole.cs

    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
    class AuthorizeRoleAttribute : AuthorizeAttribute
    {
        public AuthorizeRoleAttribute(params Rolenames[] roles)
        {
            this.Roles = string.Join(",", roles.Select(r => Enum.GetName(r.GetType(), r)));
        }
        protected override void HandleUnauthorizedRequest(System.Web.Mvc.AuthorizationContext filterContext)
        {
            if (filterContext.HttpContext.Request.IsAuthenticated)
            {
                filterContext.Result = new RedirectToRouteResult(
                new RouteValueDictionary {
                  { "action", "Unauthorized" },
                  { "controller", "Home" },
                  { "area", "" }
                  }
              );
                //base.HandleUnauthorizedRequest(filterContext);
            }
            else
            {
                filterContext.Result = new RedirectToRouteResult(
                new RouteValueDictionary {
                  { "action", "Login" },
                  { "controller", "Account" },
                  { "area", "" },
                  { "returnUrl", HttpContext.Current.Request.Url }
                  }
              );
            }
        }
    }

How to use this

[AuthorizeRole(Rolenames.Admin,Rolenames.Member)]

public ActionResult Index()
{
return View();
}
Pablo Claus
  • 5,886
  • 3
  • 29
  • 38
3

If you find yourself applying those 2 roles often you can wrap them in their own Authorize. This is really an extension of the accepted answer.

using System.Web.Mvc;

public class AuthorizeAdminOrMember : AuthorizeAttribute
{
    public AuthorizeAdminOrMember()
    {
        Roles = "members, admin";
    }
}

And then apply your new authorize to the Action. I think this looks cleaner and reads easily.

public class MyController : Controller
{
    [AuthorizeAdminOrMember]
    public ActionResult MyAction()
    {
        return null;
    }
}
GER
  • 1,870
  • 3
  • 23
  • 30
1

For "Or" you need comma between roles

[Authorize(Roles="members,admin")]

both members and admins can access

But for "and" you need

[Authorize(Roles="manager")]
[Authorize(Roles="sales")]

managers who are in sales can access.

nerkn
  • 1,867
  • 1
  • 20
  • 36
0
[Authorize(Roles="admin")]
[Authorize(Roles="members")]

will work when the AND is needed (as asked by question) whereas this answer shows the OR version. See more at https://learn.microsoft.com/en-us/aspnet/core/security/authorization/roles?view=aspnetcore-6.0#adding-role-checks

gawkface
  • 2,104
  • 2
  • 27
  • 29
-11
Intent promptInstall = new Intent(android.content.Intent.ACTION_VIEW);
promptInstall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
promptInstall.setDataAndType(Uri.parse("http://10.0.2.2:8081/MyAPPStore/apk/Teflouki.apk"), "application/vnd.android.package-archive" );

startActivity(promptInstall);
  • 1
    Answers including code should have at least a minumum description explaining how the code works and why it answers to the question. Furthermode the code section formatting needs to be improved. – Roberto Caboni Jan 03 '20 at 15:15