我们有两个 ASP.NET MVC 站点,其中一个充当另一个的 IDP。 IDP 使用 IdentityServer4。 SP 是 IDP 的 OpenIDConnect 客户端。
本周,我们收到了几位用户的报告,称他们发生了这种情况:
此时,他们会看到我们的 IDP 的“500 错误”页面。查看日志,我们可以看到 500 错误源自 IdentityServer4 中间件,错误消息为“idp 声明丢失”。
为了解决这个问题,技术支持人员一直告诉我们的用户清除浏览器的 cookie 和缓存(这让他们可以再次登录),但我们确实需要永久修复。我们不知道“徘徊”期需要多长时间才能触发该错误,但我们假设某个地方的某些令牌即将到期。开发人员无法在本地重现这种效果:我们可以将 IDP 和 SP 作为本地站点运行,并在它们之间进行连接,但从未见过此设置中的错误。这限制了我们调试它的能力。
IdentityServer4 Github 上的共识是这个问题是由于未能在startup.cs中包含这一行而导致的:
opts.OnRefreshingPrincipal = SecurityStampValidatorCallback.UpdatePrincipal;
我们尝试添加这个,但没有帮助。经过进一步调查,我们意识到我们正在使用 services.AddAspNetIdentity<T>()
,无论如何它已经做到了这一点,所以这种改变可能是多余的。这就是 UpdatePrincipal 所做的,如果这有帮助的话 - 对“idp”的引用以粗体显示:
/// <summary>
/// Maintains the claims captured at login time that are not being created by ASP.NET Identity.
/// This is needed to preserve **claims such as idp**, auth_time, amr.
/// </summary>
/// <param name="context">The context.</param>
/// <returns></returns>
public static Task UpdatePrincipal(SecurityStampRefreshingPrincipalContext context)
{
var newClaimTypes = context.NewPrincipal.Claims.Select(x => x.Type).ToArray();
var currentClaimsToKeep = context.CurrentPrincipal.Claims.Where(x => !newClaimTypes.Contains(x.Type)).ToArray();
var id = context.NewPrincipal.Identities.First();
id.AddClaims(currentClaimsToKeep);
return Task.CompletedTask;
}
IDP 上的当前设置如下所示:
services.Configure<SecurityStampValidatorOptions>(opts =>
{
opts.OnRefreshingPrincipal = SecurityStampValidatorCallback.UpdatePrincipal;
});
services
.AddTransient<IUserClaimsPrincipalFactory<MemberIdentityUser>, UserClaimsFactory>()
.AddIdentityServer(
options =>
{
options.UserInteraction.LoginUrl = "/oidc/login";
options.UserInteraction.LogoutUrl = "/oidc/logout";
})
.AddAspNetIdentity<MemberIdentityUser>()
.AddInMemoryIdentityResources(new List<IdentityResource> {
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
new IdentityResources.Email()
})
.AddDeveloperSigningCredential()
.AddSigningCredential(cert)
.AddInMemoryClients(_config.GetSection("IdentityServer:Oidc:Clients"));
我的想法是,如果这个问题是由过期的东西引起的,从而使用户处于不幸的半注销状态,那么最好的办法是在过期发生之前完全注销用户。但我不确定从哪里开始设置生命周期。据我所知,ASP.NET auth cookie(在我的浏览器中)似乎设置为“会话”,它没有到期时间。到目前为止,我们一直依赖 IdentityServer4 的相当“默认”安装,除了这个之外,并没有真正遇到问题。有谁知道还有什么可能导致这种情况/对我们在这里遇到的到期时间有什么建议吗?我确实找到了
Github 问题,他们谈论添加 UpdatePrincipal 选项,他们说:
“Cookie 在滑动时不会丢失任何声明,但如果安全标记失效,它将丢失声明。这可能是您遇到的情况吗?”但是由于我们已经设置了 UpdatePrincipal 选项,我不确定它有多相关。
果然,“UpdatePrincipal”从未运行过,因为我们使用 Umbraco,它用自己的值覆盖“SecurityStampValidatorOptions”。在 Umbraco 'MemberSecurityStampValidatorOptions' 中设置该选项解决了该问题。
您还可以使用 Umbraco 的“AddMemberIdentity”函数,它可以为您执行“ConfigureOptions”。