OWIN OpenID provider语言 - GetExternalLoginInfo() returns null



我在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

最新更新