使用 npm 包 googleapis 在对用户进行身份验证后如何获取用户的电子邮件地址?

Posted

技术标签:

【中文标题】使用 npm 包 googleapis 在对用户进行身份验证后如何获取用户的电子邮件地址?【英文标题】:With the npm package googleapis how do I get the user's email address after authenticating them? 【发布时间】:2016-08-03 20:22:37 【问题描述】:

我正在使用这个 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);
            
        );
    
;

上面的验证功能是基于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 !'
            );
        );
    
);

抛开谷歌 API 绝对荒谬的冗长,这段代码不再有效。 discover 不再是一个函数,所以我不知道如何访问包含我需要的 userinfo.get 函数的 v1v2

【问题讨论】:

如果其他人遇到这个问题,我放弃并使用带有 google oauth 策略的护照 - npmjs.com/package/passport-google-oauth20 【参考方案1】:

使用我没有权利的版本,即 2.1.6,使其工作的方法是:

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

我必须查看源代码才能弄清楚如何做到这一点,我不能 100% 确定这是否是最好的方法,因为我不得不两次提到“v2”。但它对我有用。

【讨论】:

你应该选择是使用=>还是function作为回调,所以它应该看起来像googleapis.oauth("v2").userinfo.v2.me.get(auth: oauth2Client, (e, profile) => ... ); @AndrewStroup 这是一个错字,我已经更正了。谢谢指出【参考方案2】:

我的解决方案:

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 年后,googleapis 的文档仍然令人困惑。 oauth2 = google.oauth2('v2');OAuth2 = google.auth.OAuth2; 之间的区别至关重要。我在尝试调用userinfo.get 时尝试使用OAuth2 而不是oauth2。经过几个小时的搜索,这个答案让我松了一口气。

以上是关于使用 npm 包 googleapis 在对用户进行身份验证后如何获取用户的电子邮件地址?的主要内容,如果未能解决你的问题,请参考以下文章

NPM install 的使用

npm学习之如何发布包更新发布包删除发布包

发布一个npm包

如何使用npm打包发布nodejs程序包

如何使用npm打包发布nodejs程序包

npm的使用与npm的团队建设