我正在用Angular编写一个webapp,其中身份验证由JWT令牌处理,这意味着每个请求都有一个“Authentication”头,其中包含所有必要的信息。
这对于REST调用很有效,但是我不明白应该如何处理后端托管的文件的下载链接(这些文件驻留在托管Web服务的同一台服务器上)。
我不能使用常规的<a href='...'/>
链接,因为它们不会携带任何头,认证也会失败。
我想到的一些解决方案:
1.在服务器上生成临时的不安全下载链接
1.将身份验证信息作为url参数传递,然后手动处理
1.通过XHR获取数据并保存到文件客户端。
以上所有这些都不太令人满意。
1是我现在使用的解决方案。我不喜欢它有两个原因:首先,它在安全性方面并不理想,其次,它可以工作,但需要做大量工作,尤其是在服务器上:要下载一些东西,我需要调用一个服务来生成一个新的“随机”url,将其存储在某个地方(可能在DB上)一段时间,然后将其返回给客户端。2客户端获得url,并使用window.open或类似的方法。3当请求时,新的url应该检查它是否仍然有效,然后返回数据。
2似乎至少有同样多的工作。
3看起来工作量很大,即使使用可用的库,也有很多潜在的问题。(我需要提供自己的下载状态栏,在内存中加载整个文件,然后要求用户在本地保存文件)。
这个任务看起来是一个非常基本的任务,所以我想知道是否有更简单的东西可以使用。
我不一定要寻找一个解决方案“Angular 的方式”。常规的Javascript将是好的。
5条答案
按热度按时间t2a7ltrp1#
下面是使用download属性、fetch API和URL.createObjectURL在客户机上下载该文件的一种方法:使用JWT获取文件,将有效负载转换为blob,将blob放入objectURL,将锚标记的源设置为该objectURL,然后在javascript中单击该objectURL。
download
属性的值将是最终的文件名。如果需要,您可以从内容处置响应头as described in other answers中挖掘预期的文件名。a0x5cqrl2#
技术
基于Auth0的Matias Woloski(著名的JWT传道者)的this advice,我通过使用Hawk生成一个签名请求来解决这个问题。
引用Woloski的话:
解决这个问题的方法是像AWS那样生成一个签名请求。
此技术的Here you have an example,用于激活链接。
后端
我创建了一个API来签署我的下载网址:
请求:
回复:
有了签名的URL,我们就可以得到文件
请求:
回复:
前端(通过jojoyuji)
这样,您只需单击一次即可完成所有操作:
798qvoo83#
一个替代现有的“fetch/createObjectURL”和“download-token”方法是一个标准的Form POST,目标是一个新窗口。一旦浏览器读取了服务器响应中的附件标题,它将关闭新标签并开始下载。同样的方法也适用于在新标签中显示PDF等资源。
这对旧的浏览器有更好的支持,避免了管理一种新的令牌类型。这也比URL上的基本认证有更好的长期支持,因为浏览器正在删除URL上的用户名/密码支持。
在 * 客户端 ,我们使用
target="_blank"
来避免导航,即使在失败的情况下,这对SPA(单页面应用程序)特别重要。主要的警告是, 服务器端 * JWT验证必须从POST数据中获取标记,而不是从头部中获取标记。如果您的框架使用Authentication头部自动管理对路由处理程序的访问,则可能需要将处理程序标记为未验证/匿名,以便您可以手动验证JWT以确保正确的授权。
表单可以动态创建并立即销毁,以便正确清理(注意:这可以在普通JS中完成,但为了清楚起见,这里使用JQuery)-
只需添加任何需要作为隐藏输入提交的额外数据,并确保它们已追加到表单中。
g2ieeal74#
詹姆斯答案的纯JS版本
5cg8jx4n5#
我会生成用于下载的令牌。
在angular中,发出一个经过验证的请求来获取一个临时令牌(比如一个小时),然后将其作为get参数添加到url中,这样你就可以用任何你喜欢的方式下载文件(window.open ...)