使用npm包googleapis,如何在用户认证后获取其电子邮件地址?

10
我正在使用这个npm库 - https://www.npmjs.com/package/googleapis,并且我正在使用以下Express路由作为/user/:
/* Redirect to the google login page */
  router.get('/login', function (req, res) {
    res.redirect(auth.generateUrl());
  });

  /* The callback from the google OAuth API call */
  router.get('/callback', function (req, res) {
    auth.authenticate(req.query.code);

    res.send();
  });

auth是这个模块:

var oAuth2 = require('googleapis').auth.OAuth2;

var oauth2Client = new oAuth2([CLIENT_ID], [CLIENT_SECRET], [DOMAIN] + '/user/callback');

module.exports = {
    /**
     * Generate a url to redirect to for authenticating via Google
     *
     * @return {String}
     */
    generateUrl: function () {
        return oauth2Client.generateAuthUrl({
            access_type: 'online', // 'online' (default) or 'offline' (gets refresh_token)
            scope: ['https://www.googleapis.com/auth/userinfo.email'] // If you only need one scope you can pass it as string
        });
    },
    authenticate: function (code) {
        oauth2Client.getToken(code, function (err, tokens) {
            console.log(err);

            // Now tokens contains an access_token and an optional refresh_token. Save them.
            if (!err) {
                console.log(tokens);

                oauth2Client.setCredentials(tokens);
            }
        });
    }
};

上面的authenticate函数基于https://www.npmjs.com/package/googleapis#retrieve-access-token示例。
现在,如果我进入/user/login,我会看到Google登录页面,并要求我授权。我上面使用了电子邮件范围,但是我没有在返回的tokens对象中看到我的电子邮件地址。这是我得到的结果:
{ access_token: '[72 length string]',
  token_type: 'Bearer',
  id_token: '[884 length string]',
  expiry_date: [integer timestamp] }

这不是获取电子邮件地址的方法吗?文档并不是很清晰,我在网上找到的示例教程通常只涉及谷歌的某个特定服务,比如日历。我只对基本身份验证感兴趣。我无法在文档中找到可能获得范围信息的其他方法。
还有一个小细节,当用户登录时,每个请求都必须调用getToken()吗?
编辑: 在库的代码中进行了一些挖掘后,我发现了这个:
this.userinfo = {

    /**
     * oauth2.userinfo.get
     *
     * @desc Get user info
     *
     * @alias oauth2.userinfo.get
     * @memberOf! oauth2(v1)
     *
     * @param  {object=} params - Parameters for request
     * @param  {callback} callback - The callback that handles the response.
     * @return {object} Request object
     */
    get: function(params, callback) {
      var parameters = {
        options: {
          url: 'https://www.googleapis.com/oauth2/v1/userinfo',
          method: 'GET'
        },
        params: params,
        requiredParams: [],
        pathParams: [],
        context: self
      };

      return createAPIRequest(parameters, callback);
    }

这段代码在node_modules/googleapis/apis/oauth2/v1.jsnode_modules/googleapis/apis/oauth2/v1.js中都有。然而,这似乎不是require('googleapis').auth.OAuth2使用的内容,它是node_modules/google-auth-library/lib/auth/oauth2client.js。有没有一种方法可以访问userinfo.get进一步编辑 我找到了这个教程 - https://www.theodo.fr/blog/2014/06/dont-bother-with-keys-open-your-door-with-google-api/,其中的这部分(页面底部附近)正是我想要做的事情:
googleapis.discover('oauth2', 'v1').execute(function(err, client) {
    if (!err) {
        client.oauth2.userinfo.get().withAuthClient(oauth2Client).execute(function(err, results) {
            var email = results.email;

            if ((email.indexOf('theodo.fr') + 'theodo.fr'.length) != email.length) {
                return res.send({
                    status: -1,
                    message: "Google Plus authentication failed (domain mismatch)"
                });
            }

            doorClient.open();

            res.send({
                status: 0,
                message: 'Door opened. Welcome !'
            });
        });
    }
});

暂且不谈Google API的绝对冗长,这段代码已经失效。 discover 不再是一个函数,所以我不知道如何访问包含我需要的 userinfo.get 函数的 v1v2


如果其他人遇到了这个问题,我放弃了并使用了带有Google OAuth策略的Passport - https://www.npmjs.com/package/passport-google-oauth20 - Gnuffo1
2个回答

11

我目前拥有的版本是2.1.6,使其正常工作的方法是:

googleapis.oauth2("v2").userinfo.v2.me.get({auth: oauth2Client}, (e, profile) => {
    ...
});

我不得不查看源代码才能弄清楚如何完成它,而且我不确定这是否是最好的方法,因为我必须两次提到“v2”。但对我来说它有效。


你应该选择使用 =>function 作为回调函数,因此代码应该像这样:googleapis.oauth("v2").userinfo.v2.me.get({auth: oauth2Client}, (e, profile) => { ... }); - Andrew Stroup
@AndrewStroup 这是一个打字错误,我已经更正了。感谢您指出。 - Comtaler

4

我的解决方案:

const google = require('googleapis');

const oauth2 = google.oauth2('v2');
const OAuth2 = google.auth.OAuth2;

exports.getUserInfo = (accessToken) => {
  // CLIENT_ID and CLIENT_SECRET are optional
  const authClient = new OAuth2(/* CLIENT_ID, CLIENT_SECRET */);

  authClient.setCredentials({
    access_token: accessToken,
  });

  return new Promise((resolve, reject) => {
    oauth2.userinfo.get({
      auth: authClient,
    }, (err, data) => (err ? reject(err) : resolve(data)));
  });
};

3
在过去的三年中,GoogleAPI文档仍然令人困惑。 oauth2 = google.oauth2('v2');OAuth2 = google.auth.OAuth2; 之间的区别非常重要。我试图在调用userinfo.get时使用OAuth2而不是oauth2。经过几个小时的搜索,这个答案让我松了一口气。 - Rezwan Azfar Haleem

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接