我们一直在.NET Core 2.2应用程序&中使用Cookie身份验证.通过Microsoft外部第三方提供商验证其身份后登录用户.就在最近,我们发现此工作流程中存在一个错误,指出:
Microsoft.AspNetCore.Authentication.MicrosoftAccount.MicrosoftAccountHandler:Information: Error from RemoteAuthentication: Correlation failed..”
我们将其范围缩小到以下情况:如果用户已经登录到其Microsoft帐户(只有一个帐户已登录/处于活动状态)…,然后他们登录到我们的网站,则无需登录即可自动登录选择他们的帐户名称或任何其他互动方式.此外,如果用户点击其帐户名,则会触发另一个登录请求,我相信由于请求/响应Cookie发生冲突,导致出现“ Correlation failed ..”错误.
尽管我们的实际托管提供程序位于Azure(App Services)中,但我可以从localhost重现该问题.
我已经研究了以下Microsoft文档中提到的一些解决方案/方法,其中提到了负载平衡器和代理服务器(转发标头)的配置…以及在ASP.NET Core中实施HTTPS:
https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-2.1
这些似乎没有解决问题的根源,据我了解,这是对Microsoft提供程序进行安全性质询时用户帐户的自动登录/选择.
这是我们的Startup.cs服务配置中的第三方身份验证配置的摘录.
// Authentication is added via Cookie
services.ConfigureApplicationCookie(options => options.LoginPath = "/Login");
services.AddAuthentication(opts =>
{
opts.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
opts.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(opts =>
{
opts.Cookie.SecurePolicy = CookieSecurePolicy.Always;
opts.LoginPath = "/auth/login";
opts.LogoutPath = "/auth/logout";
opts.ClaimsIssuer = "<ISSUER_HERE>"; // *** redacted for privacy
})
.AddMicrosoftAccount(options =>
{
options.ClientId = Configuration["Authentication:ApplicationId"];
options.ClientSecret = Configuration["Authentication:Password"];
options.Events.OnRemoteFailure = ctx =>
{
// React to the error here. See the notes below.
ctx.Response.Redirect("/error?FailureMessage=" + UrlEncoder.Default.Encode(ctx.Failure.Message));
ctx.HandleResponse();
return Task.FromResult(0);
};
});
理想情况下,可以防止“自动登录”行为,因此用户必须从Microsoft帐户选择提示中选择他们的帐户(即使他们以前已经登录).
现在,我们将用户重定向到错误页面,我们可以在其中清除所有cookie,并让用户重新尝试登录.如果他们在登录过程中不断选择他们的用户帐户,就会出现问题.两个请求都冲突.
任何见解将不胜感激!
解决方法:
好吧,我知道了.
似乎有点骇人听闻,但嘿,它可行.
.AddMicrosoftAccount(options =>
{
// Your configuration here
options.Events.OnRedirectToAuthorizationEndpoint = context =>
{
context.HttpContext.Response.Redirect(context.RedirectUri + "&prompt=select_account");
return Task.FromResult(0);
};
})