简体   繁体   中英

Using ASP.NET Role Authorisation with IdentityServer3 implicit flow

My single page application uses OidcTokenManager to connect to an IdentityServer3 STS using implicit flow. The client presents the IDS3 access token to a ASP.NET Core (WebApi) web service as a Bearer Token; the web service application is configured to use IDS3 middleware and restricts access to its methods using an Authorize attribute.

SPA client configuration:

function configureTokenManager() {
    console.log("configureTokenManager()");
    var config = {
        authority: $config.authority,
        client_id: "BNRegistry",
        redirect_uri: $config.webRoot + "/#/authorised/",  
        post_logout_redirect_uri: $config.webRoot + "/#/",

        response_type: "id_token token",
        scope: "openid profile email BNApi",

        silent_redirect_uri: $config.webRoot + "/#/renew/",
        silent_renew: true,

        filter_protocol_claims: false
    };
    return new OidcTokenManager(config);
};

Scope configuration in STS:

new Scope
    {
        Name = "BNApi",
        DisplayName = "BN Api",
        Enabled = true,
        Type = ScopeType.Resource,
        Claims = new List<ScopeClaim>
        {
            new ScopeClaim(Constants.ClaimTypes.Name),
            new ScopeClaim(Constants.ClaimTypes.Role)
        }
    }

WebApi configuration:

app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
    {
        Authority = Configuration["Authority"],
        RequiredScopes = new[] {"BNApi"},
        NameClaimType = IdentityModel.JwtClaimTypes.Name,                
        RoleClaimType = IdentityModel.JwtClaimTypes.Role
    });

WebApi method:

[Authorize]
public IActionResult Get()
{
    ...
}

This works as expected, rejecting an unauthenticated user with a 401. If I examine the claims for the user in the api controller method, (eg. User.Claims.ToList() ), it contains entries for any roles to which the user has been assigned.

However, if I examine the User.Identity.Name property it is always null, and if I query User.IsInRole("Administrator") it is always false, even when the user is assigned to that role. Further, if I add a role name to the Authorize attribute ( [Authorize(Role="Administrator")] ), users are rejected with a 401 whether or not they belong to the stated role.

How can I get IdentityServer3 to play nicely with ASP.NET Role authorisation?

Have you tried resetting the InboundClaimTypeMap ?

From the IdentityServer3 documentation page here :

When you inspect the claims on the about page, you will notice two things: some claims have odd long type names and there are more claims than you probably need in your application.

The long claim names come from Microsoft's JWT handler trying to map some claim types to .NET's ClaimTypes class types.

Unfortunately this mapping ends up breaking the specific claim names you have defined as name and role , because their names get transformed and no longer map to what you were expecting. This results in the [Authorize(Roles = "")] and User.IsInRole("") not working as expected.

In your API Startup.cs you should add the following:

JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>();

app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions()
{
    ...
});

EDIT: The below information was incorrect!. As pointed out by @Paul Taylor "the AlwaysInclude property ensures that the relevant claim is always present in an identity token (which is used with the client, not the API). This is a resource scope so the property has no effect.". Thanks for helping me understand a little more about how IdentityServer works :-)

For the Name and Role claims to be included when accessing the API, you need to specifically mark them as alwaysInclude in your ScopeClaim list.

 
 
 
  
  new Scope { Name = "BNApi", DisplayName = "BN Api", Enabled = true, Type = ScopeType.Resource, Claims = new List<ScopeClaim> { new ScopeClaim(Constants.ClaimTypes.Name, true), //<-- Add true here new ScopeClaim(Constants.ClaimTypes.Role, true) // and here! } }
 
 

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