在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来识别用户?
2条答案
按热度按时间a0zr77ik1#
Google OAuth返回的
access_token
不是一个JWT。它是一个不透明的字符串,只对Google有意义,您可以使用它来通过Google API识别用户。您可以使用Google People API来获取有关用户的信息。使用access_token
,您可以查询Google People API并获取有关用户的信息ghhaqwfi2#
找到了解决办法。
请求其他范围
一开始我只是请求Google日历权限。
诀窍是要求
email
,以及profile
,如果您请求这些额外的作用域,Google会返回一个包含
access_token
和refresh_token
的id_token
您可以从该id_token获取用户电子邮件和其他信息。
您可以在本地解码令牌,因为它来自与Google的安全https会话,并且您检查传回的
state
变量是否与系统生成的变量匹配。快速说明-一次请求多个作用域会出现这种难看的复选框界面,用户必须手动单击您请求的作用域的复选框。
最好让他们先登录谷歌,这将赠款电子邮件和配置文件的范围,然后要求日历范围或额外的范围,一次一个,这将提出漂亮的一次点击接受界面。
我还没有尝试过@sh_gosha建议将
access_token
发送到Google People API,但我认为这也会起作用,但它会添加一个额外的API调用。