8

I'm using roles in my ASP.NET Web API 2 project to limit access to certain resources.

Now I have the following scenario: A clubmanager can only do a GET for a club that he manages. A clubmanager should not be authorized to access clubs that he does not manage.

This is the method that gets a club:

[Authorize(Roles = "ClubManager")]
[Route("{clubId}")]
public Club GetClub(int clubId)

As you can see I only allow a user with the role "ClubManager" to access this resource. But I also have to make sure the user is manager of the club with the given clubId in the route parameter. Can I achieve this with the Authorize attribute? Or is my only option to do this check within the method itself?

Tom
  • 83
  • 1
  • 3

4 Answers4

4

You could do this with a custom AuthorizeAttribute, for example:

public class ClubAuthoriseAttribute : System.Web.Http.AuthorizeAttribute
{
    protected override bool IsAuthorized(HttpActionContext actionContext)
    {
        int clubId;
        int.TryParse((string) actionContext.ActionArguments["clubId"], out clubId);

        if (!UserCanManageClub(clubId))
        {
            return false;
        }

        return base.IsAuthorized(actionContext);
    }
}

And then use this new attribute instead:

[ClubAuthorise(Roles = "ClubManager")]
[Route("{clubId}")]
public Club GetClub(int clubId)

Note, this is assuming the parameter is named clubId, but you should have enough here to customise it to your needs.

DavidG
  • 113,891
  • 12
  • 217
  • 223
  • 1
    @NightOwl888 Thanks for the edit, but I'm English, and here we spell things correctly :) – DavidG Jan 04 '18 at 17:44
  • 1
    Well, it was either that or change the one above the `GetClub` method - they didn't match. But hey, the whole .NET framework is American English, so deal with it (I have the same reservations about Java that favors British). – NightOwl888 Jan 04 '18 at 17:46
  • @DavidG how are you maintaining the link between manager and club? i.e. the implementation of UserCanManageClub. Is it in a database table(s) or have you been able to manage it using your open id provider? – Pat Long - Munkii Yebee Oct 26 '20 at 13:54
  • @PatLong-MunkiiYebee Not sure why you're asking me, I only answered the question that was asked. Either way, if you have specific questions, you should be asking them in a new post. – DavidG Oct 26 '20 at 14:01
  • @DavidG i realise it was theoretical as it wasn't your problem to solve I just wondered if you had any thoughts on how. WRT "new post" are you saying I should ask it in a "reply" to this SO question? – Pat Long - Munkii Yebee Oct 26 '20 at 14:04
  • @PatLong-MunkiiYebee You have 3k rep, you should by now know how to ask and answer questions on this site. – DavidG Oct 26 '20 at 14:05
2

In my case, the ActionArguments property was not yet filled in the IsAuthorized method (see answer in ActionContext.ActionArguments Is Empty In IAuthenticationFilter). Instead, I was able to use

actionContext.RequestContext.RouteData.Values["clubId"]

Maybe, this helps someone in the future.

Christoph Herold
  • 1,799
  • 13
  • 18
1

In my case I don't expect an user ID to be sent from the client to my endpoint. I get the user ID from the already authorized request:

 [Authorize(Roles = "ClubManager")]
 public Club GetClub()
 {
    var userId = User.Identity.GetUserId();
    .
    .
    .
 }

And use that id to recover the actual rightful user. Like this, you wont have to worry about users trying to get other users information.

Geter Moura
  • 65
  • 1
  • 8
0

I have an idea. I think you can create additionaly your custom authorize attribute.

Smth like that:

public class AuthorizeUserToClubAttribute : AuthorizeAttribute
{   
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        bool result = false;

        //Get route data from context
        //Get current user from context
        //Ceck does user has an access and write result into variable

        return result;
    }
}