oauth-2.0 我可以从Google用户的access_token中获取他们的身份吗?

yv5phkfx  于 2022-10-31  发布在  Go
关注(0)|答案(2)|浏览(382)

在Firebase云函数中实现Google OAuth。
一切正常,但我有一个奇怪的问题。一切正常,但我不知道如何识别用户保存令牌到他们的用户对象在Firestore.
使用google API nodejs库,我使用OAuth2客户端创建了一个authURL,设置了作用域等,然后将用户重定向到它。

const {google} = require('googleapis');
const oauth2Client = new google.auth.OAuth2(
  YOUR_CLIENT_ID,
  YOUR_CLIENT_SECRET,
  YOUR_REDIRECT_URL
);

const scopes = [
    'https://www.googleapis.com/auth/calendar'
];

const authorizationUrl = oauth2Client.generateAuthUrl({
    // 'online' (default) or 'offline' (gets refresh_token)
    access_type: 'offline',
    state: 'state_parameter_gets_passed_back',
    scope: scopes,
    // Enable incremental authorization. Recommended as a best practice.
    include_granted_scopes: true
  });
console.log('created an authorizationUrl: ' + authorizationUrl);
res.redirect(authorizationUrl);

然后,我将一个https云函数端点设置为重定向URL,等待响应。
当它到来时,我得到代码并请求令牌。这也工作得很好,直到我到达saveUserToken。**谁是用户?**我的云功能只是监听响应

exports.recieveGoogleCodeFromResponseURL = functions.https.onRequest(async (req, res) => {     
  const code = req.query.code;
  console.log('got a code, it is:' + code);

  const url = require('url');
  if (req.query.code != null) {

    let userCredential;
    console.log('we have a code, trading it for tokens');

    let { tokens } = await oauth2Client.getToken(code);
    console.log({ tokens });
    oauth2Client.setCredentials(tokens);

//THIS IS THE PROBLEM HERE, who is the user to save the tokens to?
    saveUserToken(tokens, uid); //saves to Firestore
  }

  res.json({result: `Got a response from Google`, code: code, scope: req.query.scope});
});

响应如下所示:

{
access_token: "longtoken",
expiry_date: 166...,
refresh_token: "anothertoken",
scope: "https://www.googleapis.com/auth/calendar",
token_type: "Bearer"
}

据我所知,access_token和refresh_token都不是我可以解码以获取用户信息的JWT标记。
我从Google上读到的所有Firebase云函数的例子都说“在生产中,你会把这个令牌保存到一个安全的持久数据库中”,我可以用Firestore来做。我只是不知道如何识别回调和代码所属的用户。
所有显示OAuth与其他服务(Instagram、LinkedIn、Twitch)的代码示例要么结果带有用户ID,要么它们的API允许您仅使用access_token查询服务并获得用户。
例如,在这个使用Instagram登录的示例中,响应带有用户ID。

const oauth2 = instagramOAuth2Client();
const results = await oauth2.authorizationCode.getToken({
        code: req.query.code,
        redirect_uri: OAUTH_REDIRECT_URI,
      });
      functions.logger.log('Auth code exchange result received:', results);

        // We have an Instagram access token and the user identity now.
const accessToken = results.access_token;
const instagramUserID = results.user.id;

在这个来自LinkedIn的OAuth示例中,他们再次将访问令牌传递给LinkedIn端点以识别用户。

const linkedin = Linkedin.init(results.access_token);
linkedin.people.me(async (error, userResults) => {
  if (error) {
    throw error;
  }
  functions.logger.log(
    'Auth code exchange result received:',
    userResults
  );

  // We have a LinkedIn access token and the user identity now.
  const linkedInUserID = userResults.id;

我可以使用this Google library来验证ID令牌,但我无法从OAuth进程中获得ID令牌。
感觉我错过了一些简单的东西。有没有一个谷歌API,我可以传递一个access_token来识别用户?

a0zr77ik

a0zr77ik1#

Google OAuth返回的access_token不是一个JWT。它是一个不透明的字符串,只对Google有意义,您可以使用它来通过Google API识别用户。您可以使用Google People API来获取有关用户的信息。使用access_token,您可以查询Google People API并获取有关用户的信息

ghhaqwfi

ghhaqwfi2#

找到了解决办法。

请求其他范围

一开始我只是请求Google日历权限。

const scopes = 'https://www.googleapis.com/auth/calendar'

诀窍是要求email,以及profile

const scopes = 'https://www.googleapis.com/auth/calendar email profile'

如果您请求这些额外的作用域,Google会返回一个包含access_tokenrefresh_tokenid_token
您可以从该id_token获取用户电子邮件和其他信息。
您可以在本地解码令牌,因为它来自与Google的安全https会话,并且您检查传回的state变量是否与系统生成的变量匹配。

function decodeIdTokenLocally(token){
  //we split the id_token at the period ., and just decode the 2nd part
  let secondPart = token.split('.')[1];
  let localUserJsonString = atob(secondPart);
  let localUser = JSON.parse(localUserJsonString);
  return localUser
}

快速说明-一次请求多个作用域会出现这种难看的复选框界面,用户必须手动单击您请求的作用域的复选框。
最好让他们先登录谷歌,这将赠款电子邮件和配置文件的范围,然后要求日历范围或额外的范围,一次一个,这将提出漂亮的一次点击接受界面。
我还没有尝试过@sh_gosha建议将access_token发送到Google People API,但我认为这也会起作用,但它会添加一个额外的API调用。

相关问题