在多个帐户之间切换时,Gdrive API V3出现403错误

时间:2018-07-03 22:09:29

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

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

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

所以问题是这样的:

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

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

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

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

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

这里有两个问题:

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

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

感谢您的任何帮助和见解!这太痛苦了!

1 个答案:

答案 0 :(得分:0)

以下是快速解决方案:

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),然后通过节点服务器从Google请求文件。您可以将响应指定为流,然后通过内联附件发送要打开的流。

这两个链接会有所帮助:

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 App的上下文中,它可能是这样的:

...                 
$TryCount = 0
$Done = $false
do{
    # It takes a while after enabling mailbox until settings can be applied. So we need to retry.
    try{
        # If we need to execute a setting several times.
        if ($MailboxSetting.LoopOver){
            # We have a loop value (array).
            foreach ($LoopValue in $MailboxSetting.LoopOver){
                # Copy parameter as we have to change a value (loop value).
                $TempParams = $Params.PsObject.Copy()                               
                @($Params.getenumerator()) |? {$_.Value -match '#LOOPVALUE#'} |% {$TempParams[$_.Key]=$LoopValue} 
                $res = & $MailboxSetting.Command -ErrorAction Stop @TempParams -WhatIf:$RunConfig.TestMode
            }
        } else {
            $res = & $MailboxSetting.Command -ErrorAction Stop @Params -WhatIf:$RunConfig.TestMode
        }
        # Write-Log "Setting command $($MailboxSetting.Command) executed successfully"
        $Done = $true
    } catch{
        $tryCount++
        $res = Write-Error -err $error -msg "Error applying mailbox settings, account: $($AccountDetails.sAMAccountName), retry count: $($TryCount)" -Break $false
        Start-Sleep -s $(($Retires-$TryCount) * 5)

        try{
            # We may have lost the Kerberos ticket, reconnect to Exchange.
            $ConnectionType = $ExchangeSessionInfo.Type
            Disconnect-Exchange
            Connect-Exchange -TargetExchange $ConnectionType
        } catch {}          
    } 
} while ((!$done) -and ($tryCount -lt $Retires))
...

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

// 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);

});

}