ASP.net 身份在删除外部帐户后停止分发外部 Cookie
ASP.net Identity stops handing out External Cookie after removing external account
我的网站设置有四个第 3 方登录服务,Microsoft、VS、Github 和 Linkedin。一切似乎都很好,我可以毫无问题地登录 in/out、add/remove 个外部帐户。
但随机地,它似乎停止工作。当我尝试使用任何第 3 方服务登录时,它只会将我踢回登录页面。
查看 ExternalLoginCallback
似乎 AuthenticateResult.Identity
是 null
并且无法获取外部登录信息。从客户端看,他们似乎从未得到 external signin cookie
.
我仍然无法始终如一地重现此错误,因此很难确定可能发生了什么。任何帮助都会很棒。
更新 1: 我能够确定重现的步骤:
- 登录到具有超过 1 个关联登录的帐户
- 删除其中一个登录名
- 在新浏览器或私人会话中,尝试使用任何第 3 方帐户登录,您将返回到没有外部 cookie 的登录。
遇到错误后,它不会向任何新会话分发 cookie,直到 IIS 重新启动。
更新 2: 看起来与设置 Session 变量有关。
在 removeLogin
操作中,我向会话添加了一个值。我不确定为什么,但是当我停止这样做时,我的问题就停止了。是时候找出原因了... 更新 3: 看起来这个问题已经 reported to the Katana Team
更新 4: 看起来其他人已经 运行 解决了这个问题。 Whosebug post。他们没有提供解决问题所需的所有代码,因此我将在此处作为答案包含在内。
Startup.Auth.cs
public void ConfigureAuth(IAppBuilder app) {
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(appContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
// Configure the sign in cookie
app.UseCookieAuthentication(new CookieAuthenticationOptions {
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
AuthenticationMode = AuthenticationMode.Active,
LoginPath = new PathString("/Login"),
LogoutPath = new PathString("/Logout"),
Provider = new CookieAuthenticationProvider {
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, User, int>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentityCallback: (manager, user) => user.GenerateUserIdentityAsync(manager),
getUserIdCallback: (id) => (Int32.Parse(id.GetUserId()))
)
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process.
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
// Enables the application to remember the second login verification factor such as phone or email.
// Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from.
// This is similar to the RememberMe option when you log in.
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
// Uncomment the following lines to enable logging in with third party login providers
app.UseMicrosoftAccountAuthentication(new MicrosoftAccountAuthenticationOptions{
ClientId = ConfigurationManager.AppSettings["MSA:Id"],
ClientSecret = ConfigurationManager.AppSettings["MSA:Secret"],
Caption = "Microsoft"
});
app.UseVisualStudioAuthentication(new VisualStudioAuthenticationOptions(){
AppId = ConfigurationManager.AppSettings["VSO:Id"],
AppSecret = ConfigurationManager.AppSettings["VSO:Secret"],
Provider = new VisualStudioAuthenticationProvider(){
OnAuthenticated = (context) =>{
context.Identity.AddClaim(new Claim("urn:vso:access_token", context.AccessToken, XmlSchemaString, "VisualStudio"));
context.Identity.AddClaim(new Claim("urn:vso:refresh_token", context.RefreshToken, XmlSchemaString, "VisualStudio"));
return Task.FromResult(0);
}
},
Caption = "Visual Studio"
});
app.UseGitHubAuthentication(new GitHubAuthenticationOptions{
ClientId = ConfigurationManager.AppSettings["GH:Id"],
ClientSecret = ConfigurationManager.AppSettings["GH:Secret"],
Caption = "Github"
});
app.UseLinkedInAuthentication(new LinkedInAuthenticationOptions {
ClientId = ConfigurationManager.AppSettings["LI:Id"],
ClientSecret = ConfigurationManager.AppSettings["LI:Secret"],
Caption = "LinkedIn"
});
}
OWIN 和 asp.net 处理 cookies/session 的方式不同。如果您在初始化会话之前使用 OWIN 授权,则会话初始化后的任何人都将无法登录。
解决方法:将以下内容添加到您的 Global.asax
// Fix for OWIN session bug
protected void Application_AcquireRequestState() {
Session["Workaround"] = 0;
}
}
长期: OWIN 和 asp.net 处理 sessions/cookies 的方式将在 vNext 中合并,在此之前使用解决方法...
我的网站设置有四个第 3 方登录服务,Microsoft、VS、Github 和 Linkedin。一切似乎都很好,我可以毫无问题地登录 in/out、add/remove 个外部帐户。
但随机地,它似乎停止工作。当我尝试使用任何第 3 方服务登录时,它只会将我踢回登录页面。
查看 ExternalLoginCallback
似乎 AuthenticateResult.Identity
是 null
并且无法获取外部登录信息。从客户端看,他们似乎从未得到 external signin cookie
.
我仍然无法始终如一地重现此错误,因此很难确定可能发生了什么。任何帮助都会很棒。
更新 1: 我能够确定重现的步骤:
- 登录到具有超过 1 个关联登录的帐户
- 删除其中一个登录名
- 在新浏览器或私人会话中,尝试使用任何第 3 方帐户登录,您将返回到没有外部 cookie 的登录。
遇到错误后,它不会向任何新会话分发 cookie,直到 IIS 重新启动。
更新 2: 看起来与设置 Session 变量有关。
在 removeLogin
操作中,我向会话添加了一个值。我不确定为什么,但是当我停止这样做时,我的问题就停止了。是时候找出原因了... 更新 3: 看起来这个问题已经 reported to the Katana Team
更新 4: 看起来其他人已经 运行 解决了这个问题。 Whosebug post。他们没有提供解决问题所需的所有代码,因此我将在此处作为答案包含在内。
Startup.Auth.cs
public void ConfigureAuth(IAppBuilder app) {
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(appContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
// Configure the sign in cookie
app.UseCookieAuthentication(new CookieAuthenticationOptions {
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
AuthenticationMode = AuthenticationMode.Active,
LoginPath = new PathString("/Login"),
LogoutPath = new PathString("/Logout"),
Provider = new CookieAuthenticationProvider {
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, User, int>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentityCallback: (manager, user) => user.GenerateUserIdentityAsync(manager),
getUserIdCallback: (id) => (Int32.Parse(id.GetUserId()))
)
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process.
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
// Enables the application to remember the second login verification factor such as phone or email.
// Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from.
// This is similar to the RememberMe option when you log in.
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
// Uncomment the following lines to enable logging in with third party login providers
app.UseMicrosoftAccountAuthentication(new MicrosoftAccountAuthenticationOptions{
ClientId = ConfigurationManager.AppSettings["MSA:Id"],
ClientSecret = ConfigurationManager.AppSettings["MSA:Secret"],
Caption = "Microsoft"
});
app.UseVisualStudioAuthentication(new VisualStudioAuthenticationOptions(){
AppId = ConfigurationManager.AppSettings["VSO:Id"],
AppSecret = ConfigurationManager.AppSettings["VSO:Secret"],
Provider = new VisualStudioAuthenticationProvider(){
OnAuthenticated = (context) =>{
context.Identity.AddClaim(new Claim("urn:vso:access_token", context.AccessToken, XmlSchemaString, "VisualStudio"));
context.Identity.AddClaim(new Claim("urn:vso:refresh_token", context.RefreshToken, XmlSchemaString, "VisualStudio"));
return Task.FromResult(0);
}
},
Caption = "Visual Studio"
});
app.UseGitHubAuthentication(new GitHubAuthenticationOptions{
ClientId = ConfigurationManager.AppSettings["GH:Id"],
ClientSecret = ConfigurationManager.AppSettings["GH:Secret"],
Caption = "Github"
});
app.UseLinkedInAuthentication(new LinkedInAuthenticationOptions {
ClientId = ConfigurationManager.AppSettings["LI:Id"],
ClientSecret = ConfigurationManager.AppSettings["LI:Secret"],
Caption = "LinkedIn"
});
}
OWIN 和 asp.net 处理 cookies/session 的方式不同。如果您在初始化会话之前使用 OWIN 授权,则会话初始化后的任何人都将无法登录。
解决方法:将以下内容添加到您的 Global.asax
// Fix for OWIN session bug
protected void Application_AcquireRequestState() {
Session["Workaround"] = 0;
}
}
长期: OWIN 和 asp.net 处理 sessions/cookies 的方式将在 vNext 中合并,在此之前使用解决方法...