69

我创建了一个新的 MVC5 Web 应用程序,当我尝试使用 Google 或 Facebook 登录时,调用了ExternalLoginCallback中的 Action AccountController,但GetExternalLoginInfoAsync()始终返回 null:

var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
if (loginInfo == null)
{
    return RedirectToAction("Login");
}

因为它始终为空,所以它只是重定向回登录页面并重新开始该过程。我怎样才能解决这个问题?

4

17 回答 17

106

为了让 OWIN Google 登录在标准 Visual Studio 2013、ASP.Net MVC5 站点上正常工作,我必须:

  1. 在https://console.developers.google.com/project设置一个 Google OpenId 帐户

  2. 将回调 URL 设置为blah/signin-google. 关于您不需要做
    的事情的重要说明:

    • 您不需要使用 HTTPS 让 Google 重定向回来;你甚至可以重定向回普通的http://localhost,没问题。

    • 您无需为重定向 URL 设置任何内容 - Web.Config 中没有路由、控制器操作或特殊权限。重定向 URL 始终为 /signin-google,OWIN 会在幕后为您处理。

例如,如果您的网站是 me.com,您可能在 Google 开发者控制台中有以下 3 个回调 URL:

http://localhost:53859/signin-google
http://test.me.com/signin-google
https://me.com/signin-google

第一个包括 VS 为您的项目提供的任何端口号。

  1. 启用 Google+ API。这是一个隐藏的问题,是问题的根本原因这里的问题 - 如果你不这样做,很容易错过 Request to /account/ExternalLoginCallbackinclude &error=access_denied,那是因为谷歌拒绝OWIN 为用户的 Google+ 基本个人资料发出的权限请求。我不知道这是谁的错,是谷歌的还是微软的。

要在 Developers Console 中启用 Google+ API,请单击左侧的 API,搜索 Google+,单击并点击启用。是的,您确实需要这样做。如果你不这样做,你就会被水洗。

  1. 将 Google 在 Developers Console 中给您的 ClientId 和 ClientSecret 添加到 Startup.Auth,但改进过程中的代码以显式使用 OAuth2,并显式询问用户的电子邮件地址:

    var google = new GoogleOAuth2AuthenticationOptions()
    {
        ClientId = "123abc.apps.googleusercontent.com",
        ClientSecret = "456xyz",
        Provider = new GoogleOAuth2AuthenticationProvider()
    };
    google.Scope.Add("email");
    app.UseGoogleAuthentication(google);
    

而已。这终于让它工作了。

只是想再重申一次,有很多关于这个问题的答案以及 OWIN/Google 无法正常工作的问题,而且对于当前的 VS2013/MVC5/OWIN 模板来说,几乎所有这些问题都是错误的。
您根本不需要修改 Web.Config。
您不需要创建任何特殊的路线。
您不应尝试指向/signin-google不同的位置,或使用不同的回调 URL,并且绝对不应尝试将其直接绑定到/account/externallogincallbackor ,因为这些既与OWIN/Google 流程中的必要步骤externalloginconfirmation分开,也是必要的步骤。/signin-google

于 2015-04-28T13:50:01.310 回答
46

好的,我发现了为什么它为空。您必须在 Google 控制台中启用 Google + API。还要确保在将密钥粘贴到代码后,密钥末尾没有与空格连接。为什么他们不能返回正常错误?我不知道。

于 2014-12-21T01:03:58.610 回答
20

似乎 Nuget 包 Microsoft.Owin.Security.Facebook 版本 3.0.1 不再适用于 Facebook 登录。

将此包更新到预发布的 3.1.0 版本,您可以使用以下内容:

安装包 Microsoft.Owin.Security.Facebook -Pre

于 2017-03-29T18:56:43.347 回答
7

正如其他人正确提到的那样,大多数情况下是因为您没有 Google+ API 的权限,所以这里是如何在 Google API Manager 中获得对 Google+ API 的项目的权限

步骤 1.从顶部组合框中选择您的项目,然后转到仪表板 > 启用 API 在此处输入图像描述

第 2 步:搜索 Google plus 并选择它 在此处输入图像描述

第 3 步:启用它! 在此处输入图像描述

如果您返回该项目的仪表板,您可以在底部看到为该项目启用的 API 列表 在此处输入图像描述

于 2016-08-06T15:10:02.053 回答
4

我通过简单地更新应用程序中的所有 nugget 包来让它工作并且它工作。

于 2017-05-31T14:04:38.250 回答
3

我知道这很愚蠢,但经过长时间的斗争,重新启动 IIS 为我解决了这个问题。

于 2014-02-08T21:10:43.007 回答
3

这解决了我的问题:

启用 Google+ API。这是一个陷阱,是问题的根本原因 - 如果您不这样做,很容易错过 Request to /account/ExternalLoginCallbackinclude &error=access_denied,这是因为 Google 拒绝了 OWIN 为用户的权限提出的请求Google+ 基本资料。我不知道这是谁的错,是谷歌的还是微软的。

要在 Developers Console 中启用 Google+ API,请单击左侧的 API,搜索 Google+,单击它并点击启用。

于 2015-12-11T23:02:11.253 回答
1

我做了以下工作来让它工作。

登录到开发人员门户,找到您的应用程序并执行以下操作。

应用详情 > 以应用为中心的上市平台 > 网站选择“是”

于 2014-09-12T16:23:34.737 回答
1

I ran in to this issue today and it turned out that I defined the remote cookie after I assigned the providers.

Make sure you place...

app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

before...

app.UseFacebookAuthentication(
                   appId: "",
                   appSecret: "");
于 2016-10-26T20:16:04.270 回答
1

对于那些遇到 Web Api 问题的人。AuthenticationManager.GetExternalLoginInfoAsync();即使启用了 google plus api,其他解决方案也无济于事 。

使用此自定义函数获取登录信息。显然微软在通过 web api 请求时存在 GetExternalLoginInfoAsync 错误。

private async Task<ExternalLoginInfo> AuthenticationManager_GetExternalLoginInfoAsync_WithExternalBearer()
        {
            ExternalLoginInfo loginInfo = null;

            var result = await Authentication.AuthenticateAsync(DefaultAuthenticationTypes.ExternalBearer);

            if (result != null && result.Identity != null)
            {
                var idClaim = result.Identity.FindFirst(ClaimTypes.NameIdentifier);
                if (idClaim != null)
                {
                    loginInfo = new ExternalLoginInfo()
                    {
                        DefaultUserName = result.Identity.Name == null ? "" : result.Identity.Name.Replace(" ", ""),
                        Login = new UserLoginInfo(idClaim.Issuer, idClaim.Value)
                    };
                }
            }
            return loginInfo;
        }
于 2018-05-23T22:24:46.230 回答
0

经过大量搜索和挠头,以及在 Stackoverflow 上遵循众多红鲱鱼答案后,我最终在我的 Google 开发控制台上浏览了所有选项,并在 Google+API 概述页面上发现了一个蓝色的 [启用] 小按钮。我点击了这个,嘿,它工作了。忘记你读到的关于回调 url 和路由配置的所有胡说八道,OWIN 在任何情况下都会覆盖谷歌默认的 /signin-google 重定向 uri,并将你送回 ExternalLoginCallback。只要您启用 Google+API,只要坚持默认实现,一切都会好起来的。

于 2016-05-12T15:17:53.800 回答
0

对我来说,我正在将.NET 4.6.1 MVC 网站迁移到核心 1.1。在我让它工作之前工作就停止了,当我把它捡起来时,我正在迁移到 2.x。

我的问题是来自 Google 的回调是404来自我的网站的。我认为它应该命中AccountController.ExternalLoginCallback,所以我添加了一个[Route(...)],果然,谷歌的回调命中了动作。

这然后命中了null这一行中的返回(什么样的疯子返回一个null?)

var externalLoginInfo = await this.SignInManager.GetExternalLoginInfoAsync();

我对它进行了逆向工程,以在引擎盖下找到它最终得到的处理程序ExternalScheme,我的 cookie 处理程序就是为它处理程序!

这一切似乎都是错误的,我觉得中间件应该只是拦截回调 URI,所以我删除了我[Route(...)]的,404问题又回来了。

然后我发现我需要在启动时添加这个。

applicationBuilder.UseAuthentication();

这解决了404但又带来了另一个问题。

没有指定 authenticationScheme,也没有找到 DefaultSignInScheme。

通过在此处添加默认方案,我解决了上述错误。

serviceCollection.AddAuthentication(IdentityConstants.ExternalScheme)
    .AddGoogle(googleOptions => Configuration.Bind("OAuth2:Providers:Google", googleOptions))
    .AddExternalCookie();

现在AccountController.ExternalLoginCallback被一些魔法再次调用,但我回到了null返回值。

我在有问题的行上方添加了这段代码,这基本上就是幕后发生的事情(查看微软在 GitHub 上的代码)。有趣的是,h它是类型的CookieAuthenticationHandlera里面有我所有的声明和来自谷歌的信息!

var authHandler = this.HttpContext.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>();
var h = await authHandler.GetHandlerAsync(this.HttpContext, IdentityConstants.ExternalScheme);
var a = await h.AuthenticateAsync();

var externalLoginInfo = await this.SignInManager.GetExternalLoginInfoAsync();

挖掘 GitHub 并将其运行的内部代码复制粘贴到我的控制器中,我可以看到它在我的声明中找不到ClaimTypes.NameIdentifier,这是ProviderKey稍后使用的。

唔....

担心我使用的是旧的 1.xAccountController代码和更新的 2.x 标识位,我确实找到了一些仍然使用这些东西的示例,以及一些使用 Razor Pages 的示例。我会继续我所拥有的。

因此,接下来我将研究将其他 Google 用户 JSON 有效负载项映射到声明中。我认为如果我的 Google 帐户 ID(我猜是数字)被映射,那么一切都会正常工作。

https://docs.microsoft.com/en-us/aspnet/core/security/authentication/social/additional-claims?view=aspnetcore-2.2

最终修复

我终于通过添加“声明操作”将我的 Google 标识符从 Google 返回的 JSON 中提取出来解决了这个问题!

serviceCollection.AddAuthentication(IdentityConstants.ExternalScheme)
    .AddGoogle(googleOptions =>
    {
        Configuration.Bind("OAuth2:Providers:Google", googleOptions);

        googleOptions.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "sub", "string");
    })
    .AddExternalCookie();

sub字段包含最终在声明中结束的内容,nameidentifier然后进入想要的内容。ProviderKeyAccountController

于 2019-06-11T20:45:30.913 回答
0

确实,您将需要启用 Google plus。对我来说最重要的是项目 URL。在 VS 中打开属性窗口(视图 -> 属性窗口),然后右键单击项目并选择属性。在小属性窗口中复制您的 SSL URL,然后在较大的属性窗口中选择 Web 选项卡并将该 URL 粘贴到项目 URL 中。

为我解决了这个问题。

更详细地查看: https ://docs.microsoft.com/en-us/aspnet/mvc/overview/security/create-an-aspnet-mvc-5-app-with-facebook-and-google-oauth2-and -openid 登录

于 2019-04-21T03:37:45.743 回答
0

就我而言,解决方案是更新 Nuget 包 Microsoft.Owin.Security 和 Microsoft.Owin.Security.Google

于 2020-01-07T09:31:42.800 回答
0

我也想为此做出贡献。我最近才开始工作。我遇到了 GetExternalLoginInfoAsync 返回 null 但仅在生产中的问题。

经过大量搜索,我终于找到了答案,这只是我的数据库的问题。在生产中,我设置了错误的连接字符串,因此它无法正确连接,但它基本上对此保持沉默。唯一发生的事情是 GetExternallLoginInfoAsync 返回了 null。因此,如果发生这种情况,请检查您的数据库连接字符串!

同样在旁注中,唯一需要做的是:

  • 在 Google 控制台中设置项目
  • 启用 Google+ API
  • 将您的客户端 ID 和客户端密码复制到 Startup.Auth.cs 文件。

您不必启用 HTTPS,也不必创建自定义路由。但请确保您的数据库正常工作!

于 2017-01-19T11:31:36.800 回答
0

尽管上面的答案都很好,但在我的例子中,这些都没有奏效——我检查并仔细检查了谷歌设置,并同意 Chris Moschini 的观点,即有很多误导性信息。

对我来说,当我意识到我的 Out of Process 状态服务没有启动时,这是一个非常棒的时刻!没有错误(因为登录是我在重新启动后尝试的第一件事,其中状态服务设置为在机器上手动启动)只是一个 NullGetExternalLoginInfoAsync

希望这可以帮助其他人。

于 2016-02-15T13:47:06.647 回答
-1

所有其他答案都没有为我解决这个问题,所以如果您在同一条船上,请确保您的注册控制器操作具有 RequireHttps 属性:

    // GET: /Account/LoginRegister
    [AllowAnonymous]
    [RequireHttps]
    public ActionResult LoginRegister()
    {
        return View(new RegisterLoginViewModel());
    }
于 2015-10-10T00:41:07.620 回答