Как с помощью пакета npm googleapis получить адрес электронной почты пользователя после его аутентификации?

Я использую эту библиотеку npm — https://www.npmjs.com/package/googleapis. и я использую следующие экспресс-маршруты как /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] }

Разве это не способ получить адрес электронной почты? Документация не очень понятна, как и примеры руководств, которые я нашел в Интернете, поскольку они в основном касаются конкретной службы Google, например календарей. Меня интересует только базовая аутентификация. Я не могу найти никаких других методов, которые могли бы получить информацию о области действия в документации.

Незначительный момент, но должен ли я вызывать 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.js, так и в node_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 Google, этот код больше не работает. discover больше не является функцией, поэтому я понятия не имею, как получить доступ к v1 или v2, которые содержат нужную мне функцию userinfo.get.


person Gnuffo1    schedule 13.04.2016    source источник
comment
Если кто-то еще столкнется с этой проблемой, я сдался и использовал вместо этого паспорт со стратегией Google oauth - npmjs.com/package/passport-google-oauth20   -  person Gnuffo1    schedule 21.04.2016


Ответы (2)


С версией, которая у меня нет, то есть 2.1.6, способ заставить ее работать:

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

Мне нужно изучить исходный код, чтобы понять, как это сделать, и я не уверен на 100%, что это лучший способ, потому что я должен дважды упомянуть «v2». Но это работает для меня.

person Comtaler    schedule 29.04.2016
comment
вы должны выбрать, использовать ли => или function для обратного вызова, поэтому он должен выглядеть как googleapis.oauth("v2").userinfo.v2.me.get({auth: oauth2Client}, (e, profile) => { ... }); - person Andrew Stroup; 31.01.2017
comment
@AndrewStroup Это опечатка, я исправил. Спасибо, что указали на это - person Comtaler; 31.01.2017

Мое решение:

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)));
  });
};
person Moshe Simantov    schedule 19.07.2017
comment
через 3 года документы googleapis все еще сбивают с толку. Разница между oauth2 = google.oauth2('v2'); и OAuth2 = google.auth.OAuth2; имеет решающее значение. Я пытался использовать OAuth2 вместо oauth2 при вызове userinfo.get. После нескольких часов поиска этот ответ дал мне облегчение. - person Rezwan Azfar Haleem; 25.08.2020