Google的间歇性ASP.NET oAuth问题,AuthenticationManager.GetExternalIdentityAsync返回null

Tom*_*Tom 23 c# oauth-provider google-oauth asp.net-mvc-5

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

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

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

var externalIdentity = await AuthenticationManager.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);
Run Code Online (Sandbox Code Playgroud)

完整的代码是:

[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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这也是在这里.

这是一个非常间歇性的问题,重新部署应用程序通常会让它暂时起作用.

看着Fiddler,我可以看到一个电话是在签名google之前,它在找不到cookie的身份验证方法之前.

Fiddler截图

该应用使用以下代码初始化谷歌登录

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

我已在web.config中将身份验证模式设置为non,并删除了表单身份验证模块.

<system.web>
    <authentication mode="None" />
</system.web>    
<system.webServer>
    <validation validateIntegratedModeConfiguration="false" />    
    <modules runAllManagedModulesForAllRequests="true">
      <remove name="FormsAuthenticationModule" />
    </modules>
</system.webServer>
Run Code Online (Sandbox Code Playgroud)

这些站点托管在Azure上,一些站点运行在一个实例上,一些站点运行.它们具有自定义域,但在自定义域和azurewebsites域以及http/https上仍然失败.

任何人都可以帮助解决为什么会这样吗?

更新

Microsoft.Owin.Security.Google 3.0版于昨晚发布.要切换,看看这是否解决了这个问题.

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

Ram*_*y M 1

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

我正在执行以下步骤:

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

a) 客户端 ID => 它将由 google 自动生成 b) 电子邮件地址 => 将由 google 自动生成 c) 客户端密码 => 它将由 google 自动生成 d) 重定向 URI => 需要指定 url将用于处理身份验证过程的网页。在这个页面我们可以进行身份​​验证,并且可以获取用户的基本信息。

my url: "http://localhost:1822/WebForm1.aspx/code"
Run Code Online (Sandbox Code Playgroud)

我的用法:

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

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

Google Open Auth url 形成

登录后,它将重定向到“Webpage1.aspx”以及访问代码。通过将此访问代码传递给“ https://accounts.google.com/o/oauth2/token ”网址,我将获得访问令牌以及令牌类型和令牌到期时间。之后,通过将此访问权限传递给“ 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;
            }





        }
Run Code Online (Sandbox Code Playgroud)