CaTourist
CaTourist

Reputation: 733

Authorization roles WebAPI oauth owin

I implemented a token authorization system on ASP.NET Web API with OWIN middleware. I successfully can authenticate with a REST client and obtain an authorization token to call the API. If I put the [Authorize] attribute on a GET action in my controller it also works correctly. If I don't have a valid token it denies the resource with a 401 message, but if I use [Authorize(Roles="admins")] with the roles parameter, it doesn't recognize the user's roles. I verified things in the database and checked that usersinroles is correctly filled.

This is a code snippet:

[Authorize(Roles = "admins")]
public IEnumerable<CompanyModel> Get()
{
    ClaimsPrincipal principal = Request.GetRequestContext().Principal as ClaimsPrincipal;
    bool isrole = principal.IsInRole("admins");

I also checked the action without the roles parameter and the isrole boolean is always false. Do I have to enable something?

Upvotes: 23

Views: 27898

Answers (1)

Xavier Egea
Xavier Egea

Reputation: 4763

You must add in GrantResourceOwnerCredentials method:

identity.AddClaim(new Claim(ClaimTypes.Role, "admins"));

Step by step

In StartUp.cs class, you should have a custom provider, like the line

Provider = new CustomAuthorizationServerProvider()

for example:

public void ConfigureOAuth(IAppBuilder app)
{
    OAuthAuthorizationServerOptions oAuthServerOptions = new OAuthAuthorizationServerOptions
    {
        AllowInsecureHttp = true,
        TokenEndpointPath = new PathString("/token"),
        AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
        Provider = new CustomAuthorizationServerProvider()
    };

    // Token Generation
    app.UseOAuthAuthorizationServer(oAuthServerOptions);
    app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}

Then, your CustomAuthorizationServerProvider that inherits from OAuthAuthorizationServerProvider class will override GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context).

Then, after checking that the user has correct UserName and Password, you must add

var identity = new ClaimsIdentity(context.Options.AuthenticationType);
...
// other claims
...
identity.AddClaim(new Claim(ClaimTypes.Role, "admins"));
...
var ticket = new AuthenticationTicket(identity, properties);
context.Validated(ticket);

Edited

You can get user roles from DB instead of using the "admins" harcoded string doing:

var roles = await userManager.GetRolesAsync(userId);

So you can add the following method in your repository:

public async Task<IList<string>> UserRoles(string userId)
{
    IList<string> roles = await userManager.GetRolesAsync(userId);

    return roles;
}

And then call it from your overrided GrantResourceOwnerCredentials adding:

using (AuthRepository repository = new AuthRepository())
{
    IdentityUser user = await repository.FindUser(context.UserName, context.Password);

    if (user == null)
    {
        context.SetError("invalid_grant", "The user name or password is incorrect");
        return;
    }

    var roles = repository.UserRoles(user.Id);
}

Upvotes: 48

Related Questions