【问题标题】:403 errors for Gdrive API V3 when switching between multiple accounts在多个帐户之间切换时 Gdrive API V3 出现 403 错误
【发布时间】:2018-07-03 22:09:29
【问题描述】:

我正在寻找一种解决方案,帮助用户在切换帐户并点击webViewLinkwebContentLink 下载文件时绕过403 禁止。

我们将 Gdrive API V3(node) 与 Google 服务帐户一起使用。我们正在汇总文件,以便我们的团队轻松访问。服务器填充内容,然后用户通过链接访问它们。

所以问题是这样的:

  • 用户登录
  • 他们做他们的事,下载一些内容,没有问题,因为他们已登录到他们的工作帐户
  • 用户去查看他们的个人电子邮件,或从云端硬盘中获取一些东西,因此他们切换了 Google 帐户
  • 然后用户再次尝试访问内容(我们使用webContentLink/webViewLink),他们得到了 403

这完全可以理解,Google 不知道尝试访问内容的是同一个人。

我想到的一些高级解决方案:

  1. 点击链接时,添加允许任何人查看的权限,并将其设置为在 n 秒内过期(使用 permissions.create 可能无法实现)
  2. 以某种方式保存正确的身份验证并在您单击链接时使用它(意识到我不确定浏览器如何知道要发送哪个令牌)
  3. 打开“任何知道链接的人都可以查看”(出于安全原因,这是有问题的,以防有人离开公司但仍然拥有链接或有人偶然发现它)
  4. 使用服务帐户凭据向客户端添加身份验证
  5. 直接在服务器上导出和下载这些文件(可能是 .key 和其他奇怪的格式?)

许多需要访问的文件是.key.mov 等,例如.ppt 和驱动器文件/文件夹。

这里有两个(ish)问题:

  1. 解决此问题的最佳方法是什么?是否可以使用 nodejs-client 库以编程方式下载所有这些文件类型?这是委派全域权限可以解决的问题吗?

  2. 是否可以指定客户端使用哪些凭据,即使服务器正在执行所有初始身份验证?

感谢您在此提供的任何帮助和见解!这真是一种痛苦!

【问题讨论】:

  • 我不完全了解您的用例,但是,这个花絮可能会有所帮助。可以在 URL 中包含访问令牌 (?access_token=xxxxx)
  • 考虑一个简单的 UI 来查看您的驱动器文件,以便团队可以轻松访问它们,而无需实际访问驱动器和四处寻找。我查看了返回的 auth 对象,我看到了一些指向令牌的链接,但实际上都没有给我一个。如果我使用服务帐户,该令牌驻留在哪里?谢谢@pinoyyid!
  • @pinoyyid 我现在意识到您是回答类似问题的人(请参阅答案),并想知道您在哪里找到此选项以强制使用“/a/corpdomain”进行身份验证。这是在某处记录的吗?这可能会改变的事实是否也记录在某处?
  • afaik 它没有记录。如果我通过单击 Gmail 中的 GDrive 图标说 GDrive,我通过观察生成的 URL 发现了它
  • @pinoyyid 非常感谢您的回复!你是救生员!最后一个问题:由于我使用的是服务帐户,我没有获得 access_token,有没有其他方法可以在请求中指定服务帐户应该获得完全访问权限(又名 403)?

标签: node.js google-api google-drive-api google-api-nodejs-client


【解决方案1】:

这里是快速修复解决方案:

403 error from Google Drive direct link due to multiple accounts logged in

您可以使用 drive.google.com/u/1/uc?id=DOCID 或 drive.google.com/a/mycorporatedomain.com/uc?id=DOCID

但是,不要依赖这些 URL 将来不会改变。

如果您使用服务器端 API,这里有一个更强大的解决方案:

这个想法是劫持被点击的链接,获取您需要的元数据(ID、文件名、mimeType)并通过节点服务器从谷歌请求文件。您可以将响应指定为流,并通过内联附件发送要打开的流。

这两个链接会有所帮助:

node/express Force browser to download file with custom name

How to send a file from remote URL as a GET response in Node.js Express app?

在 Express 应用的上下文中,它可能如下所示:

// I'm using an async function here, but it may not be best practice.
app.get('/download', async function(req, res, next) {
  // get the metadata from req.query
  const fileId = req.query.id;
  const filename = req.query.name;
  const mimeType = req.query.mimeType;
  const inlineFilename = `inline;filename=${ filename }`;

  // Set the Content-Disposition to specify a filename
  // Set the Content-Type to accept a stream, because that's what we want back from google.
  res.set("Content-Disposition", inlineFilename);
  res.set("Content-Type", "application/octet-stream");

  // This returns a data stream from google so that we are able to pipe the result.
  const fileStream = await downloadFile(fileId);

  // Pipe the stream to the res. This sends the file stream to the client to be downloaded
  fileStream.pipe(res);

});

downloadFile 可能看起来像这样(使用google-api-nodejs-client):

downloadFile: async function(fileId) {
  try {      
    const response = await drive.files.get(
      {fileId, alt: 'media'},
      {responseType: 'stream'}
    );

    return response.data
  } catch (error) {
    console.error(error);
 }

}

【讨论】:

  • 这有什么注意事项吗?安全性,内存使用?还有什么我应该记住的吗?谢谢!
猜你喜欢
  • 1970-01-01
  • 2012-10-19
  • 1970-01-01
  • 1970-01-01
  • 2013-10-15
  • 1970-01-01
  • 2020-06-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多