如何使用基于JWT的身份validation处理文件下载?
我正在编写一个Angular Web应用程序,在这个应用程序中通过一个JWT标记来处理authentication,这意味着每个请求都有一个包含所有必要信息的“authentication”标题。
这适用于REST调用,但我不明白应该如何处理后端文件的下载链接(这些文件驻留在托pipeWeb服务的同一台服务器上)。
我不能使用常规的<a href='...'/>
链接,因为它们不会携带任何标题,authentication将失败。 window.open(...)
的各种咒语也一样。
我想到的一些解决scheme:
- 在服务器上生成临时不安全的下载链接
- 将身份validation信息作为urlparameter passing并手动处理
- 通过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 …)