【发布时间】:2021-12-23 09:31:45
【问题描述】:
我一直在将 IdentityServer 与 OIDC 中间件一起用于 asp.net core 2.1 MVC 站点以进行 Azure B2C 登录。要在 b2c 策略(singin、密码重置)之间反弹,我正在使用自定义策略 ConfigurationManager。它一直工作正常,除了不时(每隔几周)在 PolicyConfigurationManager 类的 MergeConfig 方法中引发异常。这是非常随机的,所以你永远不知道它什么时候发生。回收应用程序池可以解决问题,但几天或几周后又会再次发生。有什么线索吗?
System.NullReferenceException: Object reference not set to an instance of an object.
at IdentityServer4.WsFederation.PolicyConfigurationManager.<>c__DisplayClass7_0.<MergeConfig>b__0(SecurityKey k)
at System.Linq.Enumerable.All[TSource](IEnumerable`1 source, Func`2 predicate)
at IdentityServer4.WsFederation.PolicyConfigurationManager.MergeConfig(OpenIdConnectConfiguration result, OpenIdConnectConfiguration source)
PolicyConfigurationManager.cs
class PolicyConfigurationManager : IConfigurationManager<OpenIdConnectConfiguration>
{
private const string PolicyParameter = "p";
private readonly Dictionary<string, IConfigurationManager<OpenIdConnectConfiguration>> managers =
new Dictionary<string, IConfigurationManager<OpenIdConnectConfiguration>>();
public PolicyConfigurationManager(string authority, IEnumerable<string> policies)
{
foreach (var policy in policies)
{
var metadataAddress = $"{authority}/.well-known/openid-configuration?{PolicyParameter}={policy}";
managers.Add(policy.ToLowerInvariant(), new ConfigurationManager<OpenIdConnectConfiguration>(metadataAddress, new OpenIdConnectConfigurationRetriever()));
}
}
public async Task<OpenIdConnectConfiguration> GetConfigurationAsync(CancellationToken cancel)
{
OpenIdConnectConfiguration mergedConfiguration = null;
foreach (var manager in managers)
{
var configuration = await manager.Value.GetConfigurationAsync(cancel);
if (mergedConfiguration == null)
mergedConfiguration = Clone(configuration);
else
MergeConfig(mergedConfiguration, configuration);
}
return mergedConfiguration;
}
public Task<OpenIdConnectConfiguration> GetConfigurationByPolicyAsync(CancellationToken cancel, string policy)
{
if (string.IsNullOrEmpty(policy))
throw new ArgumentNullException(nameof(policy));
var policyKey = policy.ToLowerInvariant();
if (managers.ContainsKey(policyKey))
return managers[policyKey].GetConfigurationAsync(cancel);
throw new InvalidOperationException($"Invalid policy: {policy}");
}
private static void MergeConfig(OpenIdConnectConfiguration result, OpenIdConnectConfiguration source)
{
foreach (var alg in source.IdTokenSigningAlgValuesSupported)
{
if (!result.IdTokenSigningAlgValuesSupported.Contains(alg))
{
result.IdTokenSigningAlgValuesSupported.Add(alg);
}
}
foreach (var type in source.ResponseTypesSupported)
{
if (!result.ResponseTypesSupported.Contains(type))
{
result.ResponseTypesSupported.Add(type);
}
}
foreach (var type in source.SubjectTypesSupported)
{
if (!result.ResponseTypesSupported.Contains(type))
{
result.SubjectTypesSupported.Add(type);
}
}
foreach (var key in source.SigningKeys)
{
if (result.SigningKeys.All(k => k.KeyId != key.KeyId))
{
result.SigningKeys.Add(key);
}
}
}
public void RequestRefresh()
{
foreach (var manager in managers)
{
manager.Value.RequestRefresh();
}
}
private static OpenIdConnectConfiguration Clone(OpenIdConnectConfiguration configuration)
{
var signingKeys = new List<SecurityKey>(configuration.SigningKeys);
configuration.SigningKeys.Clear();
var keySet = configuration.JsonWebKeySet;
configuration.JsonWebKeySet = null;
var json = OpenIdConnectConfiguration.Write(configuration);
var clone = OpenIdConnectConfiguration.Create(json);
foreach (var key in signingKeys)
{
configuration.SigningKeys.Add(key);
clone.SigningKeys.Add(key);
}
configuration.JsonWebKeySet = keySet;
clone.JsonWebKeySet = keySet;
return clone;
}
}
startup.cs
\\code omitted
string[] policies = new string[] { config_AzureAdB2C_SignInPolicy, config_AzureAdB2C_ResetPasswordPolicyId };
services.AddAuthentication()
.AddOpenIdConnect("aad", "Login", options => {
options.ConfigurationManager = new PolicyConfigurationManager(config_AzureB2C_EndPointForPolicyManager, policies);
//code omitted
})
【问题讨论】:
-
请检查分配给应用程序池的私有内存和同时打开和处理线程的阈值限制。
-
您好@Flying Squirrel,如果我的回答对您有帮助,您可以点赞并接受它作为答案(点击答案旁边的复选标记,将其从灰色切换为已填充。)。这对其他社区成员可能是有益的。谢谢。
标签: identityserver4 azure-ad-b2c openid-connect