如何使用基于JWT的身份validation处理文件下载?

我正在编写一个Angular Web应用程序,在这个应用程序中通过一个JWT标记来处理authentication,这意味着每个请求都有一个包含所有必要信息的“authentication”标题。

这适用于REST调用,但我不明白应该如何处理后端文件的下载链接(这些文件驻留在托pipeWeb服务的同一台服务器上)。

我不能使用常规的<a href='...'/>链接,因为它们不会携带任何标题,authentication将失败。 window.open(...)的各种咒语也一样。

我想到的一些解决scheme:

  1. 在服务器上生成临时不安全的下载链接
  2. 将身份validation信息作为urlparameter passing并手动处理
  3. 通过XHR获取数据并保存文件客户端。

以上所有都不尽如人意。

1是我现在使用的解决scheme。 我不喜欢它有两个原因:首先它不是理想的安全明智,其次它的工作,但它需要相当多的工作,特别是在服务器上:下载一些我需要调用一个服务,产生一个新的“随机“url,将其存储在某个地方(可能在数据库上)一段时间,然后将其返回给客户端。 客户端得到的url,并使用window.open或类似的。 当请求时,新的url应该检查它是否仍然有效,然后返回数据。

2似乎至less有这么多的工作。

3似乎很多工作,即使使用可用的库,以及很多潜在的问题。 (我需要提供我自己的下载状态栏,加载整个文件在内存中,然后要求用户在本地保存文件)。

这个任务似乎是一个非常基本的,所以我想知道是否有更简单的,我可以使用。

我不一定在找“解决scheme”的解决scheme。 经常的Javascript会没事的。

技术

根据来自着名JWT传道者Auth0的Matias Woloski的build议 ,我通过与Hawk签署了一个请求来解决这个问题。

引用Woloski:

例如,解决这个问题的方法是生成一个像AWS这样的签名请求。

这里有一个这种技术的例子 ,用于激活链接。

后端

我创build了一个API来签署我​​的下载url:

请求:

 POST /api/sign Content-Type: application/json Authorization: Bearer... {"url": "https://path.to/protected.file"} 

响应:

 {"url": "https://path.to/protected.file?bewit=NTUzMDYzZTQ2NDYxNzQwMGFlMDMwMDAwXDE0NTU2MzU5OThcZDBIeEplRHJLVVFRWTY0OWFFZUVEaGpMOWJlVTk2czA0cmN6UU4zZndTOD1c"} 

使用签名的URL,我们可以获取文件

请求:

 GET https://path.to/protected.file?bewit=NTUzMDYzZTQ2NDYxNzQwMGFlMDMwMDAwXDE0NTU2MzU5OThcZDBIeEplRHJLVVFRWTY0OWFFZUVEaGpMOWJlVTk2czA0cmN6UU4zZndTOD1c 

响应:

 Content-Type: multipart/mixed; charset="UTF-8" Content-Disposition': attachment; filename=protected.file {BLOB} 

前台( jojoujiji )

通过这种方式,您可以在单个用户上单击完成:

 function clickedOnDownloadButton() { postToSignWithAuthorizationHeader({ url: 'https://path.to/protected.file' }).then(function(signed) { window.location = signed.url; }); } 

以下是使用下载属性 , 获取API和URL.createObjectURL在客户端上下载的方法 。 您将使用JWT获取文件,将有效负载转换为blob,将blob放入objectURL中,将anchor标记的源设置为objectURL,然后在javascript中单击该objectURL。

 let anchor = document.createElement("a"); let file = 'https://www.example.com/some-file.pdf'; let headers = new Headers(); headers.append('Authorization', 'Bearer MY-TOKEN'); fetch(file, { headers }) .then(response => response.blob()) .then(blobby => { let objectUrl = window.URL.createObjectURL(blobby); anchor.href = objectUrl; anchor.download = 'some-file.pdf'; anchor.click(); window.URL.revokeObjectURL(objectUrl); }); 

download属性的值将是最终的文件名。 如果需要,您可以从内容处置响应头中挖出预期的文件名,如其他答案中所述 。

我会生成令牌下载。

在angular度内做一个authentication的请求来获得一个临时的令牌(比如一个小时)然后把它作为一个get参数添加到url。 这样你可以用任何你喜欢的方式下载文件(window.open …)