.net-core - httpcontext IdentityServer4 中有时不存在自定义声明
问题描述
我们有一个问题,有时是 HttpContext 中不存在自定义声明。
public async Task<ActionResult<IEnumerable<Entity>>> GetAsync()
{
var customClaims = this.HttpContext.User.Claims // custom claims are not present
return Ok();
}
应该:
结果:
我们的配置:
我们客户的登录名和密码
public IEnumerable<Client> GetClients()
{
return new[]
{
new Client
{
ClientId = "anonym-spa",
ClientName = "anonym spa client",
AllowedGrantTypes = GrantTypes.CodeAndClientCredentials,
ClientSecrets = { new Secret(_options.CurrentValue.ClientSecret.Sha256()) },
RequireConsent = false,
RequirePkce = true,
RedirectUris = GetRedirectUris(),
PostLogoutRedirectUris = GetPostLogoutRedirectUris(),
AllowedCorsOrigins = GetAllowedCorsOrigins(),
AlwaysIncludeUserClaimsInIdToken = true,
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"anonym-api",
"oidc"
},
AllowOfflineAccess = true,
AllowPlainTextPkce = false,
AllowAccessTokensViaBrowser = true,
AccessTokenLifetime = 1209600,
}
};
}
获取发现文件
public async Task<TokenResponse?> GetToken()
{
var disco = await _httpClient.GetDiscoveryDocumentAsync().ConfigureAwait(false);
if (disco.IsError)
{
return null;
}
// request token
using var tokenRequest = new ClientCredentialsTokenRequest
{
Address = disco.TokenEndpoint,
ClientId = _options.CurrentValue.ClientId,
ClientSecret = _options.CurrentValue.ClientSecret,
Scope = _options.CurrentValue.Scope
};
var tokenResponse = await _httpClient.RequestClientCredentialsTokenAsync(tokenRequest).ConfigureAwait(false);
if (tokenResponse.IsError)
{
return null;
}
return tokenResponse;
}
客户
public void ConfigureServices(IServiceCollection services)
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = "cookie";
options.DefaultSignInScheme = "cookie";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("cookie")
.AddOpenIdConnect("oidc", options =>
{
options.Authority = Configuration.GetValue<string>("identity:Authority");
options.RequireHttpsMetadata = true;
options.ClientId = Configuration.GetValue<string>("identity:ClientId");
options.ClientSecret = Configuration.GetValue<string>("identity:ClientSecret");
options.ResponseType = "code";
options.ResponseMode = "form_post";
options.UsePkce = true;
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("anonym-api");
options.Scope.Add("offline_access");
options.GetClaimsFromUserInfoEndpoint = true;
options.ClaimActions.Add(new MapAllClaimsAction());
options.ClaimActions.MapJsonKey("website", "website");
options.ClaimActions.MapUniqueJsonKey("userNumber", "userNumber");
options.SaveTokens = true;
options.ClaimActions.MapAll();
options.Events = new OpenIdConnectEvents
{
OnTokenValidated = async ctx => await ctx.EnsureCurrentOrganizationAsync().ConfigureAwait(false),
OnRedirectToIdentityProvider = context =>
{
if (context.Properties.Items.ContainsKey("postregisterurl"))
{
context.ProtocolMessage.SetParameter("postregisterurl",
context.Properties.Items["postregisterurl"]);
}
return Task.FromResult(0);
}
};
});
使用 AlwaysIncludeUserClaimsInIdToken = true 应该始终包含自定义声明,我试图了解为什么会发生这种情况:(
解决方案
默认情况下,.NET 会删除您拥有的大部分自定义声明。只有这些声明被传递:
options.ClaimActions.MapUniqueJsonKey("sub", "sub");
options.ClaimActions.MapUniqueJsonKey("name", "name");
options.ClaimActions.MapUniqueJsonKey("given_name", "given_name");
options.ClaimActions.MapUniqueJsonKey("family_name", "family_name");
options.ClaimActions.MapUniqueJsonKey("profile", "profile");
options.ClaimActions.MapUniqueJsonKey("email", "email");
要添加,您需要使用以下代码一一手动添加:
options.ClaimActions.MapUniqueJsonKey("website", "website");
options.ClaimActions.MapUniqueJsonKey("gender", "gender");
options.ClaimActions.MapUniqueJsonKey("birthdate", "birthdate");
OpenIdConnectOptions.cs的源代码是有关此主题的丰富信息来源。
另一种方法是使用此方法:
options.ClaimActions.MapAllExcept("iss", "nbf", "exp", "aud", "nonce");
相关还使用以下方法清除声明映射:
// By default, Microsoft has some legacy claim mapping that converts
// standard JWT claims into proprietary ones. This removes those mappings.
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
JwtSecurityTokenHandler.DefaultOutboundClaimTypeMap.Clear();
推荐阅读
- php - 使用 Underscore.js 执行 PHP 片段
- kdb - q 中的 Allen 的 IntersectsWith 运算符
- java - 如何创建两个点的动画选择,就像应用程序“测量 - 快速日常测量”一样
- c# - 如何获取资源中picturebox图片的路径,并传递给标签
- sql - SQL 查询以获取每个人记录的总时间以及记录的最多时间以及哪个员工
- python - 将 line_profiler 与 numba jited 函数一起使用
- android - 在 Android Studio 更新后出现“找不到满足版本约束的 'com.android.support:support-annotations' 版本”
- html - 是否有一个网格系统对列使用基于百分比的宽度,对排水沟使用 px 值?
- python - 如何在 Python 中限制或限制数组的长度?
- c# - C# SqlKata 引擎更新查询似乎没有执行