目录
- 一、实现原理
- 二、实现步骤
- 1. nginx配置
- 2. java springboot 后台权限验证
- 2.1 权限校验文件下载
- 2.2 权限校验文件预览
- 三、扩展功能
- 1. 下载统计、访问日志
- 2. 下载限速
- 3. 防盗链
- 4. x-sendfile
@date: 2020-07-31 06:00
基于 nginx + java(springboot) 实现带权限验证的静态文件服务器,支持文件下载、pdf预览和图片预览。
需要注意的是,无需权限判断的图片不建议使用此方法,大量的图片访问会增加后台服务器的处理压力。
一、实现原理
本质上是使用了x-sendfile功能来实现,x-sendfile 是一种将文件下载请求重定向到web 服务器处理的机制,该web服务器只需负责处理请求(例如权限验证),而无需执行读取文件并发送给用户的任务。
x-sendfile可显著提高后台服务器的性能,消除了后端程序既要读文件又要处理发送的压力,尤其是处理大文件下载的情形下!
nginx也具有此功能,但实现方式略有不同。在nginx中,此功能称为x-accel-redirect。
用户请求文件,权限控制时序图:
二、实现步骤
1. nginx配置
1、静态文件通过
file_server访问,会被设置为internal,即只能内部访问不允许外部直接访问。
2、所有静态资源请求均被重定向到java后台,经过权限验证后才能访问。
# 文件下载服务
location ^~ /file_server {
# 内部请求(即一次请求的nginx内部请求),禁止外部访问,重要。
internal;
# 文件路径
alias u:/file/private/;
limit_rate 200k;
# 浏览器访问返回200,然后转由后台处理
error_page 404 =200 @backend;
}
# 文件下载鉴权
location @backend {
# 去掉访问路径中的 /file_server/,然后定义新的请求地址。
rewrite ^/file_server/(.*)$ /uecom/attach/$1 break;
# 这里的url后面不可以再拼接地址
proxy_pass http://192.168.12.68:9023;
proxy_redirect off;
proxy_set_header host $host;
proxy_set_header x-real-ip $remote_addr;
proxy_set_header x-forwarded-for $proxy_add_x_forwarded_for;
}
2. java springboot 后台权限验证
用户请求只需要传递附件参数和身份token,不再需要传递服务器的真实路径。例如:
http://192.168.12.68:9022/file_server/preview_file?id=13e9d1887b46455a96842c503c2434cb&access_token=eyjhbgcioijiuzi1nij9.eyjzdwiioij3zwjfmsisimv4cci6mtu5nje1nzkxoh0.er4yyldjimxzmnntq2gdghkyhw6i30ngzlvupumroyk
2.1 权限校验文件下载
response.setheader("x-accel-redirect", "/file_server" + attach.getattachpath()); ,重点是x-accel-redirect配置返回服务器文件的真实路径,该路径返回后由nginx内部请求处理,不会暴露给请求用户。
/**
* @describe 使用token鉴权的文件下载
* @author momo
* @date 2020-7-30 13:44
* @param id 文件唯一编码 uuid
* @return void
*/
@getmapping("/download_file")
public void downloadfile(@notnull string id) throws ioexception {
httpservletresponse response = super.gethttpservletresponse();
// 通过唯一编码查询附件
attach attach = attachservice.getbyid(id);
if (attach == null) {
// 附件不存在,跳转404
this.errorpage(404);
return;
}
// 从访问token中获取用户id。 token也可以通过 参数 access_token 传递
integer userid = userkit.getuserid();
if (userid == null || ) {
// 无权限访问,跳转403
this.errorpage(403);
return;
}
// 已被授权访问
// 文件下载
response.setheader("content-disposition", "attachment; filename=\"" + new string(attach.getattachname().getbytes("gbk"), "iso-8859-1") + "\"");
// 文件以二进制流传输
response.setheader("content-type", "application/octet-stream;charset=utf-8");
// 返回真实文件路径交由 nginx 处理,保证前端无法看到真实的文件路径。
// 这里的 "/file_server" 为 nginx 中配置的下载服务名
response.setheader("x-accel-redirect", "/file_server" + attach.getattachpath());
// 限速,单位字节,默认不限
// response.setheader("x-accel-limit-rate","1024");
// 是否使用nginx缓存,默认yes
// response.setheader("x-accel-buffering","yes");
response.setheader("x-accel-charset", "utf-8");
// 禁止浏览器缓存
response.setheader("pragma", "no-cache");
response.setheader("cache-control", "no-cache");
response.setheader("expires", "0");
}
后台可配置属性:
content-type: content-disposition: : accept-ranges: set-cookie: cache-control: expires: # 设置文件真实路径的uri,默认void x-accel-redirect: void # 限制下载速度,单位字节。默认不限速度off。 x-accel-limit-rate: 1024|off # 设置此连接的代理缓存,将此设置为no将允许适用于comet和http流式应用程序的无缓冲响应。将此设置为yes将允许响应被缓存。默认yes。 x-accel-buffering: yes|no # 如果已传输过的文件被缓存下载,设置nginx文件缓存过期时间,单位秒,默认不过期 off。 x-accel-expires: off|seconds # 设置文件字符集,默认utf-8。 x-accel-charset: utf-8
2.2 权限校验文件预览
文件下载和文件预览本质上没有区别,只是response返回时告诉浏览器执行下载还是执行打开预览。即response.setheader("content-disposition", "inline; filename="xxx.pdf");, 然后修改返回数据的格式content-type即可。
content-disposition 响应头指示回复的内容该以何种形式展示,是以内联(
inline)的形式(即网页或者页面的一部分),还是以附件(attachment)的形式下载并保存到本地。
/**
* @describe 使用token鉴权的文件预览(支持pdf和图片)
* @author momo
* @date 2020-7-30 13:44
* @param id 文件唯一编码 uuid
* @return void
*/
@getmapping("/preview_file")
public void previewfile(@notnull string id) throws ioexception {
httpservletresponse response = super.gethttpservletresponse();
// 通过唯一编码查询附件
attach attach = attachservice.getbyid(id);
if (attach == null) {
// 附件不存在,跳转404
this.errorpage(404);
return;
}
// 从访问token中获取用户id。 token也可以通过 参数 access_token 传递
integer userid = userkit.getuserid();
if (userid == null || ) {
// 无权限访问,跳转403
this.errorpage(403);
return;
}
// 已被授权访问
// 文件直接显示
response.setheader("content-disposition", "inline; filename=\"" + new string(attach.getattachname().getbytes("gbk"), "iso-8859-1") + "\"");
if ("pdf".equals(attach.getattachtype().tolowercase())) {
// pdf
response.setheader("content-type", "application/pdf;charset=utf-8");
} else {
// 图片
response.setheader("content-type", "image/*;charset=utf-8");
}
// 返回真实文件路径交由 nginx 处理,保证前端无法看到真实的文件路径。
// 这里的 "/file_server" 为 nginx 中配置的下载服务名
response.setheader("x-accel-redirect", "/file_server" + attach.getattachpath());
// 浏览器缓存 1 小时
response.setdateheader("expires", system.currenttimemillis() + 1000 * 60 * 60);
}
三、扩展功能
1. 下载统计、访问日志
// 自由发挥
2. 下载限速
// 限速,单位字节,默认不限
response.setheader("x-accel-limit-rate","1024");
3. 防盗链
//判断 referer
string referer = request.getheader("referer");
if (referer == null || !referer.startswith("https://www.itmm.wang")) {
// 无权限访问,跳转403
this.errorpage(403);
return;
}
4. x-sendfile
x-sendfile是一项功能,每个代理服务器都有自己不同的实现。
| web server | header |
|---|---|
| nginx | x-accel-redirect |
| apache | x-sendfile |
| lighttpd | x-lighttpd-send-file |
| squid | x-accelerator-vary |
使用 x-sendfile 的缺点是你失去了对文件传输机制的控制。例如如果你希望在完成文件下载后执行某些操作,比如只允许用户下载文件一次,这个 x-sendfile 是没法做到的,因为请求交给了后台,你并不知道下载是否成功。
参考资料
- x-sendfile-从web应用程序有效地提供大型静态文件
- nginx-x-accel-redirect
- nginx -xsendfile
- content-disposition
- http content-type
到此这篇关于nginx 权限控制文件预览和下载的文章就介绍到这了,更多相关nginx文件预览下载内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!