1

我正在使用带有 Passport 的 Sails 进行身份验证。我正在使用 passport-google-oauth(OAuth2Strategy) 和 passport-facebook 来启用 Google 登录。

我不太精通 Passport,如果这是一个菜鸟问题,请原谅我。我已经通过 Facebook 设置了登录,它工作得很好。使用谷歌,我在允许访问应用程序后确实收到了一个授权码,但我最终没有通过身份验证。我猜同样的代码应该适用于 Facebook 和 Google,因为这些策略都基于 oauth2。

我什至不确定要分享什么代码,因为我使用的是来自sails-generate-auth 的自动生成的代码,但是如果还有什么我可以分享的,请告诉我。

关于为什么会发生这种情况的任何想法?该应用程序是本地托管的,但这不太可能成为问题,因为无论如何我都进入了授权阶段。

4

2 回答 2

3

我遇到了同样的问题,它位于api/services/passport.js 中

// If the profile object contains a list of emails, grab the first one and
// add it to the user.
if (profile.hasOwnProperty('emails')) {
  user.email = profile.emails[0].value;
}
// If the profile object contains a username, add it to the user.
if (profile.hasOwnProperty('username')) {
  user.username = profile.username;
}

// If neither an email or a username was available in the profile, we don't
// have a way of identifying the user in the future. Throw an error and let
// whoever's next in the line take care of it.
if (!user.username && !user.email) {
  return next(new Error('Neither a username nor email was available'));
}

Google 服务没有返回profile.username属性

因此,用户没有保存在数据库中,无法进行身份验证。然后护照回调接收一个空用户,因此处理错误的函数被触发用户被重定向到登录页面

此更改允许将该displayName属性用作username

// If the profile object contains a list of emails, grab the first one and
// add it to the user.
if (profile.hasOwnProperty('emails')) {
  user.email = profile.emails[0].value;
}
// If the profile object contains a username, add it to the user.
if (profile.hasOwnProperty('username')) {
  user.username = profile.username;
}


/** Content not generated BEGIN */
// If the username property was empty and the profile object
// contains a property "displayName", add it to the user.
if (!user.username && profile.hasOwnProperty('displayName')) {
  console.log(profile);  // <= Use it to check the content given by Google about the user
  user.username = profile.displayName;
}
/** Content not generated END */


// If neither an email or a username was available in the profile, we don't
// have a way of identifying the user in the future. Throw an error and let
// whoever's next in the line take care of it.
if (!user.username && !user.email) {
  return next(new Error('Neither a username nor email was available'));
}

您也可以使用该profile.id属性,因为profile.displayName它不一定是唯一的(即:两个 Google 帐户可以有一个相同的displayName)。但在不同的服务中也是如此:Twitter帐户也可以与Facebook帐户具有相同的用户名。如果两者都在您的应用程序上注册,您将遇到错误。这是生成的代码的问题sails-generate-auth,您应该根据您想要的行为对其进行调整。

如果此解决方案也适用于您,我将提出 PR。

于 2015-07-30T11:36:31.293 回答
1

好的,所以这最终证明是 API 的一个已知问题。

TL;DR:启用此处提到的 Google+ API 和联系人 API 。(联系人 API 不是必需的,正如 @AlexisN-o 在评论中指出的那样。我的设置在禁用联系人 API 的情况下正常工作。这显然取决于您使用的范围。)

我相信这不是一个很好的失败方式,因为这是一个 API 错误,无法冒泡。无论如何,我深入passport.authenticate研究以找出问题所在。这最终会调用authenticate策略对应的包中定义的方法(本例中为 oauth2)。在这里 ( passport-google-oauth/lib/passport-google-oauth/oauth2.js) 我发现accessToken确实是从 Google 获取的,所以应该可以正常工作。这表明对令牌 URL 发出的请求存在问题。因此,我进一步冒险passport-oauth2/lib/strategy.js并最终设法记录了此错误:

{ [InternalOAuthError: failed to fetch user profile]
  name: 'InternalOAuthError',
  message: 'failed to fetch user profile',
  oauthError: 
   { statusCode: 403,
     data: '{
        "error": {
            "errors": [{
                  "domain": "usageLimits",
                  "reason": "accessNotConfigured",
                  "message": "Access Not Configured. The API (Google+ API) is not enabled for your project. Please use the Google Developers Console to update your configuration.",
                  "extendedHelp": "https://console.developers.google.com" 
            }],
            "code": 403,
            "message": "Access Not Configured. The API (Google+ API) is not enabled for your project. Please use the Google Developers Console to update your configuration." 
      }
    }'
} }

这是我寻找的结束,错误搜索的第一个结果导致了正确的答案。虽然奇怪的修复。

于 2015-07-30T18:17:07.497 回答