Google 的间歇性 ASP.NET oAuth 问题,AuthenticationManager.GetExternalIdentityAsync 返回 null [英] Intermittent ASP.NET oAuth issue with Google, AuthenticationManager.GetExternalIdentityAsync is returning null

查看:20
本文介绍了Google 的间歇性 ASP.NET oAuth 问题,AuthenticationManager.GetExternalIdentityAsync 返回 null的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试解决使用 Google 作为外部登录提供程序时出现的间歇性问题.

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

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

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

完整代码为:

[授权]公共抽象类 GoogleAccountController:TUser 所在的控制器:Microsoft.AspNet.Identity.IUser{公共 IAuthenticationManager AuthenticationManager{得到{返回 HttpContext.GetOwinContext().Authentication;}}公共抽象 UserManager用户经理{获取;放;}[允许匿名][HttpGet][路线(登录")]公共 ActionResult 登录(字符串 returnUrl){ViewData.Model = new LoginModel(){Message = TempData["message"] 作为字符串,Providers = HttpContext.GetOwinContext().Authentication.GetExternalAuthenticationTypes(),ReturnUrl = returnUrl};返回视图();}[允许匿名][HttpPost][验证AntiForgeryToken][路线(登录")]公共 ActionResult 登录(字符串提供者,字符串 returnUrl){return new ChallengeResult(provider, Url.Action("Callback", "Account", new { ReturnUrl = returnUrl }));}[允许匿名][路线(认证")]公共异步任务回调(字符串 returnUrl){var externalIdentity = await AuthenticationManager.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);如果(externalIdentity == null){return RedirectToAction("登录", new { ReturnUrl = returnUrl });}var emailAddress = externalIdentity.FindFirstValue(ClaimTypes.Email);var user = await UserManager.FindByNameAsync(emailAddress);如果(用户!= null){等待登录异步(用户,假);返回重定向到本地(returnUrl);}别的{TempData.Add("message", string.Format("帐户 {0} 未被批准.", emailAddress));return RedirectToAction("登录", new { ReturnUrl = returnUrl });}}[HttpPost][验证AntiForgeryToken][路线(注销")]公共 ActionResult 注销(字符串 returnUrl){AuthenticationManager.SignOut();返回重定向到本地(returnUrl);}私有异步任务 SignInAsync(TUser 用户, bool isPersistent){AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);var authenticationProperties = new AuthenticationProperties(){IsPersistent = isPersistent};AuthenticationManager.SignIn(authenticationProperties, identity);}私有 ActionResult RedirectToLocal(string returnUrl){如果 (Url.IsLocalUrl(returnUrl)){返回重定向(returnUrl);}别的{return RedirectToAction("Index", "Home");}}受保护的覆盖无效处置(布尔处置){如果(处理 && UserManager != null){UserManager.Dispose();用户管理器 = 空;}base.Dispose(处置);}}

这也是

解决方案

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

来自 Nuget 的引用包是失败点.

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


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

<从属程序集><assemblyIdentity name="Microsoft.Owin";publicKeyToken=31bf3856ad364e35"文化=中性"/><bindingRedirect oldVersion=0.0.0.0-3.0.1.0";newVersion=3.0.1.0";/></dependentAssembly><从属程序集><assemblyIdentity name="Microsoft.Owin.Security";publicKeyToken=31bf3856ad364e35"文化=中性"/><bindingRedirect oldVersion=0.0.0.0-3.0.1.0";newVersion=3.0.1.0";/></dependentAssembly><从属程序集><assemblyIdentity name="Microsoft.Owin.Security.Cookies";publicKeyToken=31bf3856ad364e35"文化=中性"/><bindingRedirect oldVersion=0.0.0.0-3.0.1.0";newVersion=3.0.1.0";/></dependentAssembly><从属程序集><assemblyIdentity name="Microsoft.Owin.Security.OAuth";publicKeyToken=31bf3856ad364e35"文化=中性"/><bindingRedirect oldVersion=0.0.0.0-3.0.1.0";newVersion=3.0.1.0";/></dependentAssembly></assemblyBinding>

...它又奏效了!它们可能因您使用的软件包而异,但这就是我的工作方式.

I am trying to fix an intermittent issue when using Google as an external login provider.

When attempting to login, the user is redirected back to the login page rather than being authenticated.

The problem occurs on this line (line 55 of link below), GetExternalIdentityAsync returns null.

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

The full code is:

[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);
    }
}

Which is also here.

This is very much an intermittent problem, and redeploying the app will often get it to work temporarily.

Looking in Fiddler I can see a call is made to sign-google just previous to the authenticate method in which it can't find the cookie.

The app uses the following code to initialize the google login

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

I have set the authentication mode to non in the web.config, and removed the forms authentication module.

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

The sites are hosted on Azure, some running on 1 instance, some 2. They have custom domains, although still fail on both custom domain and azurewebsites domain, and http / https.

Can anyone help with why this might be happening?

Update

Version 3.0 of Microsoft.Owin.Security.Google was released last night. Going to switch over and see if this fixes the issue.

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

解决方案

After getting the same issue for no reason, I managed to fix it by comparing 2 projects. One test project that worked no problem every time and another project I compared. I discovered that they had the exact same code, but different dll versions.

The referenced packages from Nuget were the failure point.

Make sure you have the latest packages and also check the runtime section in your web.config.


After I updated all Owin related packages and Microsoft.Owin and added:

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

... it worked again ! They might vary based on your used packages, but that's how it worked for me.

这篇关于Google 的间歇性 ASP.NET oAuth 问题,AuthenticationManager.GetExternalIdentityAsync 返回 null的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆