我正在尝试为具有 Node.js 后端的 Web 应用程序实现 Google 登录和 API 访问。 Google 的文档使用 platform.js
的组合提供了两个选项客户端和google-auth-library
服务器端:
auth2.signIn()
在客户端和 verifyIdToken()
在服务器上。)auth2.grantOfflineAccess()
,它返回一个我可以传递给服务器上的 getToken()
的代码。)我需要两者:我想通过 Google 登录对用户进行身份验证;而且,我想设置服务器身份验证,以便它也可以代表用户工作。
我无法弄清楚如何使用单个身份验证流程来做到这一点。我能得到的最接近的方法是依次执行两个操作:首先使用
signIn()
验证用户身份,然后(根据需要)通过 grantOfflineAccess()
进行第二次传递.这是有问题的:理想情况下,
signIn()
有一些变体它将离线访问添加到初始身份验证流程中并返回代码以及通常的 token ,但我什么也没看到。帮助?(编辑:我在其他地方收到的一些建议是仅实现流程 #2,然后使用安全 cookie 存储某种用户标识符,我会在每个请求中检查用户帐户。我可以看到这在功能上可以正常工作,但基本上意味着我正在滚动自己的登录系统,这似乎会增加我在关键系统中引入错误的机会。)
最佳答案
要将 API 添加到现有的 Google 登录集成,最好的选择是实现增量授权。为此,您需要同时使用 google-auth-library和 googleapis ,以便用户可以拥有这个工作流程:
为此,您用于身份验证的客户端 JavaScript 可能需要对请求进行一些更改
离线访问:
$('#signinButton').click(function() {
auth2.grantOfflineAccess().then(signInCallback);
});
在响应中,您将拥有一个带有授权码的 JSON 对象:{"code":"4/yU4cQZTMnnMtetyFcIWNItG32eKxxxgXXX-Z4yyJJJo.4qHskT-UtugceFc0ZRONyF4z7U4UmAI"}
在此之后,您可以使用一次性代码将其交换为访问 token 和刷新 token 。Here are一些工作流程细节:
The code is your one-time code that your server can exchange for its own access token and refresh token. You can only obtain a refresh token after the user has been presented an authorization dialog requesting offline access. If you've specified the select-account prompt in the OfflineAccessOptions [...], you must store the refresh token that you retrieve for later use because subsequent exchanges will return null for the refresh token
因此,您应该使用 google-auth-library在后端完成此工作流程。为了这,
您将使用身份验证代码来获取刷新 token 。但是,由于这是一个离线工作流程,
您还需要验证所提供代码的完整性,如 documentation explains :
If you use Google Sign-In with an app or site that communicates with a backend server, you might need to identify the currently signed-in user on the server. To do so securely, after a user successfully signs in, send the user's ID token to your server using HTTPS. Then, on the server, verify the integrity of the ID token and use the user information contained in the token
获取应该保留在数据库中的刷新 token 的最终函数可能如下所示
这个:
const { OAuth2Client } = require('google-auth-library');
/**
* Create a new OAuth2Client, and go through the OAuth2 content
* workflow. Return the refresh token.
*/
function getRefreshToken(code, scope) {
return new Promise((resolve, reject) => {
// Create an oAuth client to authorize the API call. Secrets should be
// downloaded from the Google Developers Console.
const oAuth2Client = new OAuth2Client(
YOUR_CLIENT_ID,
YOUR_CLIENT_SECRET,
YOUR_REDIRECT_URL
);
// Generate the url that will be used for the consent dialog.
await oAuth2Client.generateAuthUrl({
access_type: 'offline',
scope,
});
// Verify the integrity of the idToken through the authentication
// code and use the user information contained in the token
const { tokens } = await client.getToken(code);
const ticket = await client.verifyIdToken({
idToken: tokens.id_token!,
audience: keys.web.client_secret,
});
idInfo = ticket.getPayload();
return tokens.refresh_token;
})
}
此时,我们已经重构了身份验证工作流程以支持 Google API。但是,您尚未要求用户对其进行授权。由于您还需要授予离线访问权限,因此您应该通过客户端应用程序请求额外的权限。请记住,您已经需要一个事件 session 。const googleOauth = gapi.auth2.getAuthInstance();
const newScope = "https://www.googleapis.com/auth/calendar"
googleOauth = auth2.currentUser.get();
googleOauth.grantOfflineAccess({ scope: newScope }).then(
function(success){
console.log(JSON.stringify({ message: "success", value: success }));
},
function(fail){
alert(JSON.stringify({message: "fail", value: fail}));
});
您已经完成了前端更改,并且您只缺少一个步骤。使用 googleapis 在后端创建 Google API 的客户端库,您需要使用上一步中的刷新 token 。对于带有 Node.js 后端的完整工作流程,您可能会发现 my gist有帮助。
关于javascript - 单流: sign user in via Google oAuth AND grant offline/server access?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66339977/