Javascript 使用节点中的googleapis包交换访问令牌的授权码

Javascript 使用节点中的googleapis包交换访问令牌的授权码,javascript,node.js,oauth-2.0,google-oauth,google-authentication,Javascript,Node.js,Oauth 2.0,Google Oauth,Google Authentication,我正在尝试为需要googledrive访问的服务器端NodeJS应用程序实现google登录,但无法让“googleapis”google对象将授权代码交换为实际的访问令牌 我想做的事情有google文档,但我遇到的第7步是用Java和Python描述的,因此没有NodeJS google对象。我也遵循了nodeJS快速启动,但是身份验证的许多步骤是不同的。也就是说,我不能以相同的方式创建google.auth.OAuth2对象,因为我的应用程序的凭据的格式与示例的不同(它们没有重定向URI)

我正在尝试为需要googledrive访问的服务器端NodeJS应用程序实现google登录,但无法让“googleapis”google对象将授权代码交换为实际的访问令牌

我想做的事情有google文档,但我遇到的第7步是用Java和Python描述的,因此没有NodeJS google对象。我也遵循了nodeJS快速启动,但是身份验证的许多步骤是不同的。也就是说,我不能以相同的方式创建
google.auth.OAuth2
对象,因为我的应用程序的凭据的格式与示例的不同(它们没有重定向URI)

这就是我得到它的地方:

const fs = require('fs');
const { google } = require('googleapis');



formAuthClient('<PastedAuthCodeFromFrontEnd>');

async function formAuthClient(code) {
  // reads credentials from file
  const credentials = await readFile('./client_secret.json').then(JSON.parse);

  // cannot read redirect_uris like in NodeJS quickstart because these do not exist. 
  // Also, no credentials.installed, it's credentials.web
  const { client_secret, client_id } = credentials.web;
  const oAuth2Client = new google.auth.OAuth2( // form authObject
    client_id, client_secret
  );
  console.log(oAuth2Client);

  const token = await oAuth2ClientGetToken(oAuth2Client, code).catch(console.err);
  oAuth2Client.setCredentials(token);
  return oAuth2Client;
}


// just an async wrapper for fs.readFile
function readFile(file) {
  return new Promise((resolve, reject) => {
    fs.readFile(file, (err, content) => {
      if (err) reject(err);
      resolve(content);
    });
  })
}
// just an async wrapper for oAuth2Client.getToken
function oAuth2ClientGetToken(oAuth2Client, code) {
  return new Promise((resolve, reject) => {
    oAuth2Client.getToken(code, (err, token) => { // errors out here
      if (err) reject(err);
      resolve(token);
    });
  });
}
const fs=require('fs');
const{google}=require('googleapis');
formAuthClient(“”);
AuthClient的异步函数(代码){
//从文件中读取凭据
const credentials=wait readFile('./client_secret.json')。然后(json.parse);
//无法像NodeJS quickstart中那样读取重定向URI,因为这些URI不存在。
//另外,未安装credentials.installed,它是credentials.web
const{client\u secret,client\u id}=credentials.web;
const oAuth2Client=new google.auth.OAuth2(//form authObject
客户id,客户机密
);
console.log(oAuth2Client);
const token=await oAuth2ClientGetToken(oAuth2Client,code).catch(console.err);
oAuth2Client.setCredentials(令牌);
返回oAuth2Client;
}
//只是fs.readFile的异步包装器
函数readFile(文件){
返回新承诺((解决、拒绝)=>{
fs.readFile(文件,(错误,内容)=>{
如果(错误)拒绝(错误);
解决(内容);
});
})
}
//只是oAuth2Client.getToken的异步包装
函数oAuth2ClientGetToken(oAuth2Client,代码){
返回新承诺((解决、拒绝)=>{
oAuth2Client.getToken(代码,(err,token)=>{//errors out here
如果(错误)拒绝(错误);
解析(令牌);
});
});
}
运行此代码首先打印oAuth2Client对象,然后给出以下错误:


OAuth2Client{
_事件:[对象:空原型]{},
_事件提示:0,
_maxListeners:未定义,
transporter:DefaultTransporter{},
凭据:{},
certificateCache:{},
certificateExpiry:null,
certificateCacheFormat:“PEM”,
RefreshToken:映射{},
_clientId:“.apps.googleusercontent.com”,
_clientSecret:“”,
重定向URI:未定义,
阈值毫秒:300000
}
(节点:16186)未经处理的PromisejectionWarning:错误:授予无效
根据Gaxios.request(/home/miko/node/clouds/api/node_modules/Gaxios/build/src/Gaxios.js:70:23)
在处理和拒绝时(内部/process/task_queues.js:89:5)
在异步OAuth2Client.getTokenAsync(/home/miko/node/clouds/api/node_modules/google auth library/build/src/auth/OAuth2Client.js:119:21)
(节点:16186)未处理的PromisejectionWarning:未处理的承诺拒绝。此错误源于在没有catch块的异步函数中抛出,或者拒绝未使用.catch()处理的承诺。(拒绝id:1)
(节点:16186)[DEP0018]弃用警告:未处理的承诺拒绝已弃用。将来,未处理的承诺拒绝将使用非零退出代码终止Node.js进程

理想情况下,我希望top函数返回一个完全经过身份验证的客户端对象,我可以稍后使用它访问googledriveapi

为了所有在我之后出现的想法-决心 先决条件 如果您的设置与我相同,您执行的to令牌交换不是在前端浏览器中,而是在后端设置中。我做了以下事情,似乎解决了问题

1> 在Google Cloud platform>API&Services>Credentials>(您的oauth客户端ID。)>授权的JavaScript源代码中添加辅助主机名/端口。使用您的web应用URI

例如,如果您的react代码使用localhost:3000,而localhost:3002。你需要同时做广告。这也适用于您的生产设置

2> 授权码只能一次性使用。一旦您使用它,如果您没有存储刷新令牌/访问令牌。您需要要求用户再次进行身份验证。它给出了完全相同的信息

3> 您可以持有授权令牌的时间似乎有一段暂停时间。谷歌可以比我更好地回答这个问题,但是我注意到,如果我将一个合法授权令牌存储超过一个小时,并且它给了我与上面相同的消息,那么我也会遇到同样的错误

我的建议是发送回比数据更好的错误:{error:'invalid_grant',error_description:'Bad Request'}


因为所有上述场景似乎都导致了相同的错误。调试对我来说很困难。

我在这里想出了一个解决方案

为了所有在我之后出现的想法-决心 先决条件 如果您的设置与我相同,您执行的to令牌交换不是在前端浏览器中,而是在后端设置中。我做了以下事情,似乎解决了问题

1> 在Google Cloud platform>API&Services>Credentials>(您的oauth客户端ID。)>授权的JavaScript源代码中添加辅助主机名/端口。使用您的web应用URI

例如,如果您的react代码使用localhost:3000,而localhost:3002。你需要同时做广告。这也适用于您的生产设置

2> 授权码只能一次性使用。一旦您使用它,如果您没有存储刷新令牌/访问令牌。您需要要求用户再次进行身份验证。它给出了完全相同的信息

3> 您可以持有授权令牌的时间似乎有一段暂停时间。谷歌可以比我更好地回答这个问题,但我注意到,如果我将一个合法授权令牌存储超过一个小时,我也会遇到同样的错误,它给了我同样的麻烦