前端文件下载的权限验证问题

问题介绍

在前后端分离的模式下,如果前端希望从后端下载一个文件,通常的做法是后端通过一个接口返回给前端一个下载的地址,然后前端模拟浏览器的点击事件或者调用window.open来实现文件的下载。

但是在通常情况下,后端的接口都会需要权限验证,比如要在header中添加Authorization的头,但是由于使用上述方法提到的文件下载方式并没有使用ajax请求,所以我们并不能简单的在header中添加权限验证的头。

所以,后端仅仅返回一个下载地址供前端下载的方式是不安全的,任何获取到该url的人都能够轻易的得到下载内容。

解决方案

这里介绍两种解决的方法。

  1. 依赖于jwt的机制,使得文件下载的url需要在query中添加token参数进行权限验证
  2. 利用 HTML5 File API。使用createObjectURLrevokeObjectURL方法来创建和下载文件,从而可以利用ajax来模拟实现文件下载。

基于jwt实现权限验证

例如下载地址为 /download/fileA

  1. 后端需要额外提供一个接口供用户获取下载用的token
  2. 客户端使用ajax请求该接口获取token
  3. 客户端模拟打开拼接了token的url:/download/fileA?token=xxx
  4. 后端解析该token判断用户是否有权限下载该文件
// 服务器端
const jwt = require('jsonwebtoken');
...
router.get('/download/token', (req, res) => {
  const secret = 'xxxxxx'
  const token = jwt.sign({}, secret, { expiresIn: 2 }); // 2s内有效
  return res.json({ token });
});

// 客户端
const download = async (url) => {
const { data: { token } } = await axios.get('/download/token');
let finalUrl = url;
if (url.includes('?')) {
 finalUrl += `&token=${token}`;
} else {
 finalUrl += `?token=${token}`;
}
window.open(finalUrl);
}

// 服务器端具体解析token下载文件的代码就省略了。
// jwt的使用参考jsonwebtoken库的使用

利用 HTML5 File API 实现权限验证

  1. 后端提供文件下载的接口与其他接口保证同样的权限验证策略,例如在header中验证Authorization头
  2. 前端使用ajax请求文件下载的接口
  3. 前端利用window.URL.createObjectURL将请求得到的内容转化为objectUrl
  4. 前端模拟点击,使用window.URL.revokeObjectURL(url)实现文件下载
// 客户端
const download = async (url) => {
  const response = await axios.get('/download/fileA', {headers: {Authorization: 'Token xxxxxx'}});
  const blob = new Blob([response], { type: 'text/plain;charset=utf-8' });
  const url = window.URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = [fileName];
  a.click();
  window.URL.revokeObjectURL(url);
}

你可能感兴趣的:(前端文件下载的权限验证问题)