“Role” Claim is missing from the token - NET CORE 3.1 & IS4

心不动则不痛 提交于 2020-08-10 19:23:17

问题


I have a service which is responsible for authenticating users.

After updating:

  • IdentityServer4 from 2.3.2 to 4.0.2;

an issue popped up:

  • The token does not contain the required user claims anymore.

The service is configured this way:

  • The Startup.cs contains:
applicationBuilder.UseCookiePolicy();
applicationBuilder.UseIdentityServer();
applicationBuilder.UseAuthorization();
//...
mvcCoreBuilder.AddAuthorization(ConfigureAuthorization);
var auth = mvcCoreBuilder.Services.AddAuthentication(ConfigureAuthenticationOptions);
auth.AddIdentityServerAuthentication(ConfigureIdentityServerAuthentication);
//...
void ConfigureAuthenticationOptions(AuthenticationOptions authenticationOptions)
{
    authenticationOptions.DefaultScheme = IdentityServerConstants.DefaultCookieAuthenticationScheme;
}
//...
void ConfigureAuthorization(AuthorizationOptions authorizationOptions)
{
    var requirements = new List<IAuthorizationRequirement> { new DenyAnonymousAuthorizationRequirement() };
    var schemes = new List<string> { IdentityServerConstants.DefaultCookieAuthenticationScheme };
    authorizationOptions.DefaultPolicy = new AuthorizationPolicy(requirements, schemes);
}
  • And the (Updated for IS4 4.0.2) Login controller which sets the cookie contains:
props = new _AuthenticationProperties
{
    IsPersistent = true,
    ExpiresUtc = DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration),
};

// user.Claims contains the "role" claim

var claimsIdentity = new ClaimsIdentity(user.Claims, CookieAuthenticationDefaults.AuthenticationScheme);
claimsIdentity.AddClaim(new Claim(JwtClaimTypes.Subject, user.SubjectId));
var claimsPrincipal = new ClaimsPrincipal(claimsIdentity);

// The created claimsPrincipal contains the "role" claim

await HttpContext.SignInAsync(claimsPrincipal, props);

  • Before updating the IS4 the controller looked like this:
await HttpContext.SignInAsync(user.SubjectId, props, user.Claims.ToArray());

In the api project which is being protected:

  • When trying to validate for controller requests i have (in a different api project):
// attribute for validating roles on controllers
[AuthorizeRoles(Role.SimpleRole)] // which implements IAuthorizationFilter

// And the implementation:
public void OnAuthorization(AuthorizationFilterContext context)
{
    var user = context.HttpContext.User;
    // user is of type 'ClaimsIdentity'
    // and it does not contain the "role" claim
 
    // some checks to verify the user here...
}

The startup of the protected api project contains:

builder.AddAuthorization(ConfigureAuthorization);

var auth = builder.Services.AddAuthentication(ConfigureAuthenticationOptions);

auth.AddIdentityServerAuthentication(ConfigureIdentityServerAuthentication);

The ConfigureIdentityServerAuthentication method sets some IdentityServerAuthenticationOptions. The RoleClaimType is not being set because it have a default value 'role' which is the expected one.

The IdentityServerAuthenticationOptions is from the 'IdentityServer4.AccessTokenValidation' package version 3.0.1.

Here are two screenshots to prove that the RoleClaimType is set:

  • on the authorization service on Startup.cs:

  • on the OnAuthorization method from the AuthorizeRoles attribute:

The Questions:

  • Why the token does not contain all of the claims which are added to the ClaimsIdentity object?
  • How can this be fixed in order for the token to contain the "role" claim again?

Involved Technologies:

  • Net Core 3.1
  • IdentityServer4 4.0.2

回答1:


by default IdentityServer and ASP.NET core have different opinion on what the name of the RoleClaim should be.

Add this code in your client to fix that mapping (setting the TokenValidationParameters option)

       services.AddAuthentication(options =>
        {
            options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
        }).AddCookie(options =>
        {
            options.LoginPath = "/User/Login";
            options.LogoutPath = "/User/Logout";
            options.AccessDeniedPath = "/User/AccessDenied";
        }).AddOpenIdConnect(options =>
        {
            options.Authority = "https://localhost:6001";
            options.ClientId = "authcodeflowclient";
            options.ClientSecret = "mysecret";
            options.ResponseType = "code";

            options.Scope.Clear();
            options.Scope.Add("openid");
            options.Scope.Add("profile");
            options.Scope.Add("email");
            options.Scope.Add("employee_info");


            //Map the custom claims that should be included
            options.ClaimActions.MapUniqueJsonKey("employment_start", "employment_start");
            options.ClaimActions.MapUniqueJsonKey("seniority", "seniority");
            options.ClaimActions.MapUniqueJsonKey("contractor", "contractor");
            options.ClaimActions.MapUniqueJsonKey("employee", "employee");
            options.ClaimActions.MapUniqueJsonKey("management", "management");
            options.ClaimActions.MapUniqueJsonKey(JwtClaimTypes.Role, JwtClaimTypes.Role);

            options.SaveTokens = true;
            options.SignedOutRedirectUri = "/";
            options.GetClaimsFromUserInfoEndpoint = true;



            options.TokenValidationParameters = new TokenValidationParameters
            {
                NameClaimType = JwtClaimTypes.Name,
                RoleClaimType = JwtClaimTypes.Role,

            };

            options.Prompt = "consent";
        });

Also, it can be helpful to look at the various requests in Fiddler to figure out your claim issues.

Settings this one to True can also help out:

options.GetClaimsFromUserInfoEndpoint = true;


来源:https://stackoverflow.com/questions/63016021/role-claim-is-missing-from-the-token-net-core-3-1-is4

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!