【问题标题】:Intermittent ASP.NET oAuth issue with Google, AuthenticationManager.GetExternalIdentityAsync is returning nullGoogle 出现间歇性 ASP.NET oAuth 问题,AuthenticationManager.GetExternalIdentityAsync 返回 null
【发布时间】:2014-06-30 02:36:48
【问题描述】:

我正在尝试解决将 Google 用作外部登录提供商时出现的间歇性问题。

尝试登录时,用户会被重定向回登录页面,而不是进行身份验证。

问题出现在这一行(下面链接的第55行),GetExternalIdentityAsync返回null。

var externalIdentity = await AuthenticationManager.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);

完整代码为:

[Authorize]
public abstract class GoogleAccountController<TUser> : Controller where TUser : Microsoft.AspNet.Identity.IUser
{
    public IAuthenticationManager AuthenticationManager
    {
        get
        {
            return HttpContext.GetOwinContext().Authentication;
        }
    }

    public abstract UserManager<TUser> UserManager { get; set; }

    [AllowAnonymous]
    [HttpGet]
    [Route("login")]
    public ActionResult Login(string returnUrl)
    {
        ViewData.Model = new LoginModel()
        {
            Message = TempData["message"] as string,
            Providers = HttpContext.GetOwinContext().Authentication.GetExternalAuthenticationTypes(),
            ReturnUrl = returnUrl
        };

        return View();
    }

    [AllowAnonymous]
    [HttpPost]
    [ValidateAntiForgeryToken]
    [Route("login")]
    public ActionResult Login(string provider, string returnUrl)
    {
        return new ChallengeResult(provider, Url.Action("Callback", "Account", new { ReturnUrl = returnUrl }));
    }

    [AllowAnonymous]
    [Route("authenticate")]
    public async Task<ActionResult> Callback(string returnUrl)
    {
        var externalIdentity = await AuthenticationManager.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);

        if (externalIdentity == null)
        {
            return RedirectToAction("Login", new { ReturnUrl = returnUrl });
        }

        var emailAddress = externalIdentity.FindFirstValue(ClaimTypes.Email);
        var user = await UserManager.FindByNameAsync(emailAddress);

        if (user != null)
        {
            await SignInAsync(user, false);

            return RedirectToLocal(returnUrl);
        }
        else
        {
            TempData.Add("message", string.Format("The account {0} is not approved.", emailAddress));

            return RedirectToAction("Login", new { ReturnUrl = returnUrl });
        }
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    [Route("logout")]
    public ActionResult Logout(string returnUrl)
    {
        AuthenticationManager.SignOut();

        return RedirectToLocal(returnUrl);
    }

    private async Task SignInAsync(TUser user, bool isPersistent)
    {
        AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);

        var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
        var authenticationProperties = new AuthenticationProperties()
        {
            IsPersistent = isPersistent
        };

        AuthenticationManager.SignIn(authenticationProperties, identity);
    }

    private ActionResult RedirectToLocal(string returnUrl)
    {
        if (Url.IsLocalUrl(returnUrl))
        {
            return Redirect(returnUrl);
        }
        else
        {
            return RedirectToAction("Index", "Home");
        }
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing && UserManager != null)
        {
            UserManager.Dispose();
            UserManager = null;
        }

        base.Dispose(disposing);
    }
}

这也是here

这是一个非常间歇性的问题,重新部署应用程序通常会使其暂时工作。

在 Fiddler 中我可以看到在它找不到 cookie 的身份验证方法之前调用了 sign-google。

应用使用以下代码初始化google登录

app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
        LoginPath = new PathString("/login")
    });
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
app.UseGoogleAuthentication();

我在web.config中将认证模式设置为non,并移除了forms认证模块。

<system.web>
    <authentication mode="None" />
</system.web>    
<system.webServer>
    <validation validateIntegratedModeConfiguration="false" />    
    <modules runAllManagedModulesForAllRequests="true">
      <remove name="FormsAuthenticationModule" />
    </modules>
</system.webServer>

这些站点托管在 Azure 上,一些在 1 个实例上运行,一些在 2 个实例上运行。 他们有自定义域,尽管在自定义域和 azurewebsites 域以及 http / https 上仍然失败。

谁能帮助解释为什么会发生这种情况?

更新

Microsoft.Owin.Security.Google 3.0 版于昨晚发布。打算切换一下,看看这是否能解决问题。

https://www.nuget.org/packages/Microsoft.Owin.Security.Google

【问题讨论】:

  • 我刚刚遇到了一个类似的间歇性 oAuth 问题,这是由我所连接的 API 网络上的负载均衡器引起的。可能会给你一些其他的东西来研究(除了你的代码)。

标签: c# asp.net-mvc-5 google-oauth oauth-provider


【解决方案1】:

在无缘无故遇到同样的问题后,我设法通过比较 2 个项目来解决它。一个每次都没有问题的测试项目和我比较的另一个项目。我发现它们的代码完全相同,但 dll 版本不同。

来自 Nuget 的引用包是故障点。

确保您拥有最新的软件包,并检查 web.config 中的 runtime 部分。


在我更新了所有 Owin 相关包和 Microsoft.Owin 并添加:

<assemblyBinding>
  <dependentAssembly>
    <assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
    <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
  </dependentAssembly>
  <dependentAssembly>
    <assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral" />
    <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
  </dependentAssembly>
  <dependentAssembly>
    <assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" culture="neutral" />
    <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
  </dependentAssembly>
  <dependentAssembly>
    <assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" culture="neutral" />
    <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
  </dependentAssembly>
</assemblyBinding>

...它再次起作用了! 它们可能会根据您使用的软件包而有所不同,但这就是我的工作方式。

【讨论】:

    【解决方案2】:

    我忘记在 Google 开发者控制台中启用“Google + API”。 Google 登录似乎没问题,但 GetExternalLoginInfoAsync 返回 null。

    您可以点击此链接 https://stackoverflow.com/a/27631109/657926

    【讨论】:

      【解决方案3】:

      Microsoft 的 System.Web 的 Owin 实现中存在错误。在 IIS 上运行 Owin 应用程序时使用的一种。如果我们将新的基于 Owin 的身份验证处理与 ASP.NET MVC5 一起使用,那么我们可能 99% 的人都会这样做。

      该错误使 Owin 设置的 cookie 在某些情况下神秘消失。

      把这个nuget放在https://github.com/KentorIT/owin-cookie-saver之前 app.UseGoogleAuthentication(...)

      【讨论】:

        【解决方案4】:

        Tom 我通过使用 REST API 在我的 asp.net 应用程序中使用 google-oauth。它工作正常,我没有遇到任何连接问题。

        我正在执行以下步骤:

        1.我在谷歌开发者控制台中创建了一个项目,我创建了设置“Web 应用程序的客户端 ID”,其中包含以下参数。

        a)Client ID => 将由 google 自动生成 b)Email地址=> google会自动生成 c)Client secret=> 由google自动生成 d) 重定向 URIs => 需要指定用于处理身份验证过程的网页 url。在这个页面我们可以进行认证,我们可以获取用户的基本信息。

        my url: "http://localhost:1822/WebForm1.aspx/code"
        

        我的用法:

        1. 我创建了一个示例项目,其中包含“Webpage1.aspx”和“Webpage2.aspx”。

        我已经设置了“Webpage2.aspx”启动页面,我正在“Webpage2.aspx”中形成开放的身份验证网址并重定向到谷歌登录页面。

        登录后,它会重定向到“Webpage1.aspx”以及访问代码。通过将此访问代码传递给“https://accounts.google.com/o/oauth2/token”url,我将获得访问令牌以及令牌类型和令牌到期时间。之后,通过将此访问权传递给“https://www.googleapis.com/oauth2/v2/userinfo”网址,我将获得用户基本信息,例如“电子邮件、姓名、性别、照片等......)

        示例代码

            public class GoogleAuthorizationData
            {
                public string access_token { get; set; }
                public int expires_in { get; set; }
                public string token_type { get; set; }
        
            }
        
          public class GoogleUserInfo
            {
                public string name { get; set; }
                public string family_name { get; set; }
                public string gender { get; set; }
                public string email { get; set; }
                public string given_name { get; set; }
                public string picture { get; set; }
                public string link { get; set; }
                public string id { get; set; }
        
            }
        
          Webpage1.aspx
          ============
         protected void Page_Load(object sender, EventArgs e)
                {
                    string code = Request.QueryString["code"].ToString();
                    string scope = Request.QueryString["scope"].ToString();
                    string url = "https://accounts.google.com/o/oauth2/token";
                    string postString = "code=" + code + "&client_id=" + ConfigurationManager.AppSettings["GoogleClientID"].ToString() + "&client_secret=" + ConfigurationManager.AppSettings["GoogleSecretKey"].ToString() + "&redirect_uri=" + ConfigurationManager.AppSettings["ResponseUrl"].ToString() + "&grant_type=authorization_code";
        
                    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url.ToString());
                    request.Method = "POST";
                    request.ContentType = "application/x-www-form-urlencoded";
        
                    UTF8Encoding utfenc = new UTF8Encoding();
                    byte[] bytes = utfenc.GetBytes(postString);
                    Stream os = null;
                    try
                    {
                        request.ContentLength = bytes.Length;
                        os = request.GetRequestStream();
                        os.Write(bytes, 0, bytes.Length);
                    }
                    catch
                    { }
        
                    try
                    {
                        HttpWebResponse webResponse = (HttpWebResponse)request.GetResponse();
                        Stream responseStream = webResponse.GetResponseStream();
                        StreamReader responseStreamReader = new StreamReader(responseStream);
                        var result = responseStreamReader.ReadToEnd();//
                        var json = new JavaScriptSerializer();
        
                        GoogleAuthorizationData authData = json.Deserialize<GoogleAuthorizationData>(result);
        
                        HttpWebRequest request1 = (HttpWebRequest)WebRequest.Create("https://www.googleapis.com/oauth2/v2/userinfo");
                        request1.Method = "GET";
                        request1.ContentLength = 0;
                        request1.Headers.Add("Authorization", string.Format("{0} {1}", authData.token_type, authData.access_token));
                        HttpWebResponse webResponse1 = (HttpWebResponse)request1.GetResponse();
                        Stream responseStream1 = webResponse1.GetResponseStream();
                        StreamReader responseStreamReader1 = new StreamReader(responseStream1);
                        GoogleUserInfo userinfo = json.Deserialize<GoogleUserInfo>(responseStreamReader1.ReadToEnd());
                       Response.Write(userinfo.email);
        
                    }
                    catch (Exception eX)
                    {
                        throw eX;
                    }
        
        
        
        
        
                }
        

        【讨论】:

          【解决方案5】:

          我认为你不应该使用app.UseGoogleAuthentication();,因为这是一个尝试使用 OpenID 2.0 的调用,has been deprecated
          你应该改用OAuth 2.0 for Login (OpenID Connect)
          所以:

          1. 在 Google Developers Console 中注册您的应用
          2. 启用它以访问 Google+ API(即使您不打算直接使用 Google+ - 它现在被用作身份验证的手段)
          3. 以这种方式启用 ASP.NET Identity 的 Google 身份验证
          app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()  
          {  
              ClientId = "YOUR_CLIENT_ID",  
              ClientSecret = "YOUR_CLIENT_SECRET",  
          });
          

          【讨论】:

          • 我们确实尝试过这个,因为现在更新版本的 Microsoft.Owin.Security.Google 需要这样做,但是我们仍然遇到了同样的问题
          【解决方案6】:

          我也有同样的问题。我正在使用 Visual Studio 2013,网站在 Azure 上。社交登录一直在正常工作而没有问题停止工作,并且 LinkLoginCallback 在 loginInfo 中接收到 null。我在没有更改代码或重建的情况下重新发布了该项目,然后 loginInfo 收到了正确的数据并且一切正常。没有意义,但你去。

          【讨论】:

            【解决方案7】:

            确保已启用第 3 方 cookie。我发现,如果您在尝试使用您的应用程序“注册”用户时没有登录谷歌,它会重定向到登录页面,因为它会寻找不存在的这个 cookie,但仍然设法做它需要与外部提供商。下次您尝试“注册”时,因为它已完成流程的一部分,它不再需要查找外部 cookie,因此第二次成功。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2019-04-16
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-04-21
              • 2017-01-16
              相关资源
              最近更新 更多