我在ASP中有OWIN OpenId提供程序的问题。NET MVC5应用程序。NET身份验证,基于VS2013模板,采用个人用户身份验证。Google和LinkedIn的OWIN OpenID提供程序用于登录认证。
问题是,似乎是非常随机的;GetExternalLoginInfo()在LoginConfirmation回调时返回null,即使登录认证成功。
var authManager = HttpContext.Current.GetOwinContext().Authentication;
var login = authManager.GetExternalLoginInfo();
正在使用的提供商是Google (Microsoft.Owin.Security. Google)。Google 2.1.0)和LinkedIn(来自Owin.Security.Providers 1.3),这两个提供商都会导致同样的问题。
有时它失败一次,然后再次工作,但有时它只是继续失败,直到AppPool被回收。
当前应用程序的两个实例托管在同一Windows Azure虚拟机上的IIS中。每个实例都有自己的AppPool,但设置相同(不同的子域)。有时,登录在一个实例上停止工作,但在另一个实例上仍然工作。
这个问题在本地也出现了(IIS Express - VS2013)。
有人遇到过OWIN OpenID身份验证的类似问题吗?
Startup.Auth.cs如下所示:
public void ConfigureAuth(IAppBuilder app)
{
// Enable the application to use a cookie to store information for the signed in user
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
});
// Use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
app.UseGoogleAuthentication();
app.UseLinkedInAuthentication("clientId", "clientSecret");
}
正在使用以下OWIN nuget包:
<package id="Microsoft.AspNet.Identity.Core" version="1.0.0" targetFramework="net45" />
<package id="Microsoft.AspNet.Identity.Owin" version="1.0.0" targetFramework="net45" />
<package id="Microsoft.Owin" version="2.1.0" targetFramework="net45" />
<package id="Microsoft.Owin.Host.SystemWeb" version="2.1.0" targetFramework="net45" />
<package id="Microsoft.Owin.Security" version="2.1.0" targetFramework="net45" />
<package id="Microsoft.Owin.Security.ActiveDirectory" version="2.1.0" targetFramework="net45" />
<package id="Microsoft.Owin.Security.Cookies" version="2.1.0" targetFramework="net45" />
<package id="Microsoft.Owin.Security.Facebook" version="2.1.0" targetFramework="net45" />
<package id="Microsoft.Owin.Security.Google" version="2.1.0" targetFramework="net45" />
<package id="Microsoft.Owin.Security.Jwt" version="2.1.0" targetFramework="net45" />
<package id="Microsoft.Owin.Security.MicrosoftAccount" version="2.1.0" targetFramework="net45" />
<package id="Microsoft.Owin.Security.OAuth" version="2.1.0" targetFramework="net45" />
<package id="Microsoft.Owin.Security.Twitter" version="2.1.0" targetFramework="net45" />
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net45" />
<package id="Owin" version="1.0" targetFramework="net45" />
<package id="Owin.Security.Providers" version="1.3" targetFramework="net45" />
<package id="System.IdentityModel.Tokens.Jwt" version="3.0.2" targetFramework="net45" />
ASP.NET_SessionId
cookie缺失时出现问题
在重定向到OpenID提供者的凭据之前在会话中设置一个虚拟值似乎可以解决问题:
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
Session["dummy"] = "dummy"; // Create ASP.NET_SessionId cookie
return View();
}
更多细节请参考:https://stackoverflow.com/a/21234614/205023
接受的答案并没有为我解决问题;真正起作用的是在Google开发者控制台的API管理器中启用"Google+ API"
对于我来说,将ControllerContext.HttpContext.Session.RemoveAll();
放在AccountController和ManageController中,解决了问题:
public ActionResult ExternalLogin(string provider, string returnUrl)
{
ControllerContext.HttpContext.Session.RemoveAll();
// Request a redirect to the external login provider
return new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl }));
}
和
public ActionResult LinkLogin(string provider)
{
ControllerContext.HttpContext.Session.RemoveAll();
// Request a redirect to the external login provider to link a login for the current user
return new AccountController.ChallengeResult(provider, Url.Action("LinkLoginCallback", "Manage"), User.Identity.GetUserId());
}
正确的方法是更新解决方案中所有自己的组件。
我正在使用SecuritySwitch来设置安全和非安全页面,我的问题的原因是/sign -google路径被重定向到非安全请求,而不是使用安全请求。
我在所有OpenIdConnect实现中都遇到了这个问题-让它工作的关键是确保身份验证选项包括OpenIdConnectResponseType.CodeIdToken的ResponseType。这是我创业的一个例子。身份验证:
Public Sub ConfigureAuth(app As IAppBuilder)
app.CreatePerOwinContext(AddressOf ApplicationDbContext.Create)
app.CreatePerOwinContext(Of ApplicationUserManager)(AddressOf ApplicationUserManager.Create)
app.CreatePerOwinContext(Of ApplicationSignInManager)(AddressOf ApplicationSignInManager.Create)
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType)
app.UseCookieAuthentication(New CookieAuthenticationOptions() With {
.AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
.Provider = New CookieAuthenticationProvider() With {
.OnValidateIdentity = SecurityStampValidator.OnValidateIdentity(Of ApplicationUserManager, ApplicationUser)(
validateInterval:=TimeSpan.FromMinutes(30),
regenerateIdentity:=Function(manager, user) user.GenerateUserIdentityAsync(manager))},
.LoginPath = New PathString("/Account/Login")})
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie)
Dim facebookOptions = New FacebookAuthenticationOptions With {
.AppId = ConfigurationManager.AppSettings("FacebookClientID"),
.AppSecret = ConfigurationManager.AppSettings("FacebookClientSecret"),
.Provider = New FacebookAuthenticationProvider With {
.OnAuthenticated = Function(context)
context.Identity.AddClaim(New Claim("Provider", "Facebook"))
context.Identity.AddClaim(New Claim("provider:name", context.Identity.FindFirstValue(ClaimTypes.Name)))
context.Identity.AddClaim(New Claim("provider:accesstoken", context.AccessToken, ClaimValueTypes.String, "Facebook"))
context.Identity.AddClaim(New Claim("provider:picture", String.Format("//graph.facebook.com/{0}/picture?type=square", context.User.Value(Of String)("id"))))
Dim email = context.Identity.FindFirstValue(ClaimTypes.Email)
If email IsNot Nothing Then
context.Identity.AddClaim(New Claim("provider:email", email))
Else
Dim fb = New Facebook.FacebookClient(context.AccessToken)
Dim myInfo = fb.Get("/me?fields=email")
email = myInfo("email")
If email IsNot Nothing Then
context.Identity.AddClaim(New Claim("provider:email", email))
Else
Throw New ArgumentNullException("myInfo.Email")
End If
End If
Return Task.FromResult(0)
End Function}}
facebookOptions.Scope.Add("email")
app.UseFacebookAuthentication(facebookOptions)
app.UseGoogleAuthentication(New GoogleOAuth2AuthenticationOptions() With {
.ClientId = ConfigurationManager.AppSettings("GoogleClientID"),
.ClientSecret = ConfigurationManager.AppSettings("GoogleClientSecret"),
.Provider = New GoogleOAuth2AuthenticationProvider With {.OnAuthenticated = Function(context)
context.Identity.AddClaim(New Claim("Provider", "Google"))
context.Identity.AddClaim(New Claim("provider:name", context.Identity.FindFirstValue(ClaimTypes.Name)))
context.Identity.AddClaim(New Claim("provider:email", context.Identity.FindFirstValue(ClaimTypes.Email)))
context.Identity.AddClaim(New Claim("provider:accesstoken", context.AccessToken, ClaimValueTypes.String, "Google"))
context.Identity.AddClaim(New Claim("provider:picture", context.User.SelectToken("image")?.Value(Of String)("url")))
Return Task.FromResult(0)
End Function}})
app.UseLinkedInAuthentication(New LinkedInAuthenticationOptions With {
.ClientId = ConfigurationManager.AppSettings("LinkedInClientID"),
.ClientSecret = ConfigurationManager.AppSettings("LinkedInClientSecret"),
.Provider = New LinkedInAuthenticationProvider With {.OnAuthenticated = Function(context)
context.Identity.AddClaim(New Claim("Provider", "LinkedIn"))
context.Identity.AddClaim(New Claim("provider:name", context.Name))
context.Identity.AddClaim(New Claim("provider:email", context.Email))
context.Identity.AddClaim(New Claim("provider:accesstoken", context.AccessToken, ClaimValueTypes.String, "LinkedIn"))
context.Identity.AddClaim(New Claim("provider:picture", context.User.SelectToken("pictureUrl").ToString))
Return Task.FromResult(0)
End Function}})
Dim oktaOptions = New OpenIdConnect.OpenIdConnectAuthenticationOptions With {
.AuthenticationType = "okta",
.SignInAsAuthenticationType = "Cookies",
.Authority = ConfigurationManager.AppSettings("okta:Authority"),
.ResponseType = Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectResponseType.CodeIdToken,
.ClientId = ConfigurationManager.AppSettings("okta:ClientId"),
.ClientSecret = ConfigurationManager.AppSettings("okta:ClientSecret"),
.RedirectUri = ConfigurationManager.AppSettings("okta:RedirectUri"),
.TokenValidationParameters = New Microsoft.IdentityModel.Tokens.TokenValidationParameters With {.ValidateIssuer = True},
.Scope = "openid profile email"
}
app.UseOpenIdConnectAuthentication(oktaOptions)
Dim auth0Options = New OpenIdConnect.OpenIdConnectAuthenticationOptions With {
.AuthenticationType = "auth0",
.SignInAsAuthenticationType = "Cookies",
.Authority = ConfigurationManager.AppSettings("auth0:Authority"),
.ResponseType = Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectResponseType.CodeIdToken,
.ClientId = ConfigurationManager.AppSettings("auth0:ClientId"),
.ClientSecret = ConfigurationManager.AppSettings("auth0:ClientSecret"),
.RedirectUri = ConfigurationManager.AppSettings("auth0:RedirectUri"),
.TokenValidationParameters = New Microsoft.IdentityModel.Tokens.TokenValidationParameters With {.ValidateIssuer = True},
.Scope = "openid profile email"
}
app.UseOpenIdConnectAuthentication(auth0Options)
app.MapSignalR
GlobalHost.DependencyResolver.Register(GetType(IUserIdProvider), Function() New MySignalRIdProvider())
End Sub