"Role" 令牌中缺少声明 - NET CORE 3.1 和 IS4
"Role" Claim is missing from the token - NET CORE 3.1 & IS4
我有一项服务负责对用户进行身份验证。
更新后:
- IdentityServer4 从 2.3.2 到 4.0.2;
弹出一个问题:
- 令牌不再包含所需的用户声明。
服务是这样配置的:
- Startup.cs 包含:
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);
}
- 设置 cookie 的(针对 IS4 4.0.2 更新的)登录控制器包含:
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);
- 在更新 IS4 之前,控制器看起来像这样:
await HttpContext.SignInAsync(user.SubjectId, props, user.Claims.ToArray());
在被保护的api项目中:
- 当我尝试验证控制器请求时(在不同的 api 项目中):
// 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...
}
受保护的 api 项目的启动包含:
builder.AddAuthorization(ConfigureAuthorization);
var auth = builder.Services.AddAuthentication(ConfigureAuthenticationOptions);
auth.AddIdentityServerAuthentication(ConfigureIdentityServerAuthentication);
ConfigureIdentityServerAuthentication
方法设置了一些IdentityServerAuthenticationOptions
。未设置 RoleClaimType
,因为它具有默认值 'role'
,这是预期的值。
IdentityServerAuthenticationOptions
来自 'IdentityServer4.AccessTokenValidation' 包版本 3.0.1。
这里有两张截图证明 RoleClaimType
已设置:
在 Startup.cs 的授权服务上:
在 AuthorizeRoles
属性的 OnAuthorization 方法上:
问题:
- 为什么令牌不包含添加到 ClaimsIdentity 对象的所有声明?
- 如何解决这个问题才能使令牌再次包含“角色”声明?
涉及技术:
- 网络核心 3.1
- IdentityServer4 4.0.2
默认情况下,IdentityServer 和 ASP.NET 核心对 RoleClaim 的名称应该有不同的看法。
在您的客户端中添加此代码以修复该映射(设置 TokenValidationParameters 选项)
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";
});
此外,查看 Fiddler 中的各种请求有助于找出您的索赔问题。
将此设置为 True 也有帮助:
options.GetClaimsFromUserInfoEndpoint = true;
我有一项服务负责对用户进行身份验证。
更新后:
- IdentityServer4 从 2.3.2 到 4.0.2;
弹出一个问题:
- 令牌不再包含所需的用户声明。
服务是这样配置的:
- Startup.cs 包含:
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);
}
- 设置 cookie 的(针对 IS4 4.0.2 更新的)登录控制器包含:
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);
- 在更新 IS4 之前,控制器看起来像这样:
await HttpContext.SignInAsync(user.SubjectId, props, user.Claims.ToArray());
在被保护的api项目中:
- 当我尝试验证控制器请求时(在不同的 api 项目中):
// 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...
}
受保护的 api 项目的启动包含:
builder.AddAuthorization(ConfigureAuthorization);
var auth = builder.Services.AddAuthentication(ConfigureAuthenticationOptions);
auth.AddIdentityServerAuthentication(ConfigureIdentityServerAuthentication);
ConfigureIdentityServerAuthentication
方法设置了一些IdentityServerAuthenticationOptions
。未设置 RoleClaimType
,因为它具有默认值 'role'
,这是预期的值。
IdentityServerAuthenticationOptions
来自 'IdentityServer4.AccessTokenValidation' 包版本 3.0.1。
这里有两张截图证明 RoleClaimType
已设置:
在 Startup.cs 的授权服务上:
在
AuthorizeRoles
属性的 OnAuthorization 方法上:
问题:
- 为什么令牌不包含添加到 ClaimsIdentity 对象的所有声明?
- 如何解决这个问题才能使令牌再次包含“角色”声明?
涉及技术:
- 网络核心 3.1
- IdentityServer4 4.0.2
默认情况下,IdentityServer 和 ASP.NET 核心对 RoleClaim 的名称应该有不同的看法。
在您的客户端中添加此代码以修复该映射(设置 TokenValidationParameters 选项)
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";
});
此外,查看 Fiddler 中的各种请求有助于找出您的索赔问题。
将此设置为 True 也有帮助:
options.GetClaimsFromUserInfoEndpoint = true;