简体   繁体   中英

Authorize Attribute with Roles not working?

I am trying to get this working, but no luck so far. My Authorize attribute works on its own, but once i state a Role that the user must be apart of, then i get the following message returned from my webapi

{"message":"Authorization has been denied for this request."}

Startup.cs

public void Configuration(IAppBuilder app)
{
    //HttpConfiguration config = new HttpConfiguration();

    ConfigureOAuth(app);

    // simple injector
    SimpleInjectorConfig.Register();

    AutoMapperConfig.RegisterMappings();
    AreaRegistration.RegisterAllAreas();
    GlobalConfiguration.Configure(WebApiConfig.Register);
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);

    app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
}

public void ConfigureOAuth(IAppBuilder app)
{
    OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
    {
        AllowInsecureHttp = true,
        TokenEndpointPath = new PathString("/token"),
        AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
        Provider = new SimpleAuthorizationServerProvider(new AccountService(new DataContext()))
    };

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

}

SimpleAuthorizationServerProvider.cs

public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
    private AccountService _service;

    public SimpleAuthorizationServerProvider(AccountService service)
    {
        _service = service;
    }

    public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
    {
        context.Validated();
    }


    public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {

        context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });

        User user = await _service.FindUserAsync(context.UserName, context.Password);

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


        var identity = new ClaimsIdentity(context.Options.AuthenticationType);
        identity.AddClaim(new Claim("sub", context.UserName));
        //identity.AddClaim(new Claim("role", "user"));

        context.Validated(identity);

    }
}

Decorating a controller method, i use

[Authorize(Roles="CanViewCompany")]

If i use just this, it works and returns the data i would expect

[Authorize]

My basic User class

public class User : IdentityUser<long, UserLogin, UserRole, UserClaim>, IUser<long>
{
    public User()
        : base()
    {
        this.Groups = new HashSet<UserGroup>();
    }

    public virtual ICollection<UserGroup> Groups { get; set; }

}

I am sure i am missing something, but i just aint sure what. Any help much appreciated

it seems to be this function that was causing the error. I was not setting the username (which didnt make it break, but the User property didnt have one, which i am sure i will need in future).

Also i was not adding any roles. I am not sure if this is the right way to fix this, but it works.

If someone knows of a better/right way to do this, let me know.

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {

        context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });

        User user = await _service.FindUserAsync(context.UserName, context.Password);

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

        var identity = new ClaimsIdentity(context.Options.AuthenticationType);
        identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
        identity.AddClaim(new Claim(ClaimTypes.Role, "CanViewCompany"));
        identity.AddClaim(new Claim(ClaimTypes.Role, "CanAddCompany"));
        identity.AddClaim(new Claim(ClaimTypes.Role, "CanEditCompany"));
        identity.AddClaim(new Claim(ClaimTypes.Role, "CanDeleteCompany"));

        context.Validated(identity);

    }

This won't scale if you have newer roles, you need to create this dynamically, please check my answer to this SO question which is very identical for your case but check how you get user roles from DB not to hard-code them, what you are currently doing is assigning the same roles for all authenticated users which makes no sense.

I guess this code is taken from http://bitoftech.net posts about authorization, if this is the case then please remove the below LOC which dose not make sense in your case as well.

 identity.AddClaim(new Claim("sub", context.UserName));

I think that you have a little problem with your aproach. Any user will have all roles...

My solution was as follows:

1) To obtain the claims array through the CreateIdentityAsync function:

    var claims = await _service.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);

2) Add the claims array to the identity object:

identity.AddClaims(claims.Claims);

Displaying the code together...

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {

        context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });

        User user = await _service.FindUserAsync(context.UserName, context.Password);

        if (user == null)
        {
            context.SetError("invalid_grant", "The user name or password is incorrect.");
            return;
        }
        var claims = await _service.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);

        var identity = new ClaimsIdentity(context.Options.AuthenticationType);
        identity.AddClaims(claims);

        context.Validated(identity);
    }

That's all.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM