3

Further information can be provided if required, first post here!

I'm currently managing a website in asp.net mvc4 with the standard role authorisation(webpages_roles/webpages_usersinroles) functionality.

This works fine to a point, actionresults within controllers are decorated as appropriate with tags such as:

[Authorize(Roles = "Admin")]

or where one of multiple roles can access:

[Authorize(Roles = "Admin, Manager")]

What I need to do, is to authorize multiple roles, a situation of "AND" rather than "OR". E.g. the user must be both in the "Manager" role and the "Finance" role to access a controller. Users with only "Manager" or only "Finance" but not both mustn't be able to access the action result.

How would this be achieved? Search results show people talk about extending the authorize attribute but if there is specific advice on how to do that or something more straight forward it in this case it would be very useful!

Spike's solution worked with a minor modification, the for each was using var to create a char datatype, the IsInRole function required a string

Final code:

public class AndAuthorize : AuthorizeAttribute
{

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        IPrincipal user = httpContext.User;

        try
        {
            if (Roles != null && Roles.Any())
            {
                foreach (string r in Roles.Split(','))
                {
                    if (!user.IsInRole(r))
                        return false;
                }
            }
            return true;
        }
        catch (Exception ex)
        {
            return false;
        }

    }
}
Zerk
  • 1,595
  • 9
  • 16

2 Answers2

3

Yes, the best way to deal with that is extending the Authorize attribute.

The following is an example of an Authorize class that you can implement to the "AND"

public class AndAuthorize : AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        try
        {
            if (Roles != null && Roles.Any())
            {
                foreach(var role in Roles){
                if(!httpContext.User.IsInRole(role))
                    return false;
                }
            }
            return true;
        }
        catch (Exception ex)
        {
            return false;
        }
    }
}

Now you just have to set [AndAuthorize(Roles = "Admin, Manager")], because extending the authorize class, will give you access to the default attributes (Roles an Users).

You can then use the original Authorize for the "OR" and this one to the "AND" cases

C-JARP
  • 1,028
  • 14
  • 16
  • Thanks for the help Spike, This was 99% perfect, i just had to make a slight modification to the code. I'll edit the original post to highlight the issue and solution. – Zerk Apr 27 '15 at 23:29
  • Ah yes, you are totally right, i forgot that roles is not an array but a string :D My bad! Glad i could help :) – C-JARP Apr 28 '15 at 08:58
1

I haven't tried but should work for checking two roles.

Basically, you could apply one attribute to authorize controller and the other for the action method.

[Authorize(Roles = "Manager")] //role1
public class YourController : Controller
{
    [Authorize(Roles = "Finance")] //role2
    public ActionResult Index()
    {
    }
}

If you have different combinations:

[Authorize(Roles = "role1, role2, role3")] 
public class YourController : Controller
{
    [Authorize(Roles = "role4, role5, role6")]  
    public ActionResult Index()
    {
    }
}
Kaf
  • 33,101
  • 7
  • 58
  • 78
  • Thanks for the suggestion, unfortunately as it stands some ActionResults within the controller would require the parent role and some wouldn't. It's a shame as this would have been a quick and easy solution! – Zerk Apr 27 '15 at 23:37