服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

云服务器|WEB服务器|FTP服务器|邮件服务器|虚拟主机|服务器安全|DNS服务器|服务器知识|Nginx|IIS|Tomcat|

服务器之家 - 服务器技术 - Nginx - NGINX 权限控制文件预览和下载的实现原理

NGINX 权限控制文件预览和下载的实现原理

2022-07-22 13:28隔壁老瓦 Nginx

我们知道,使用nginx作为文件下载服务器,可以极大地降低对后端Java服务器的负载冲击,但是nginx本身并不提供授权控制,这下该如何操作呢,下面小编给大家带来了NGINX 权限控制文件预览和下载的实现原理,感兴趣的朋友跟随小编一起

@date: 2020-07-31 06:00

基于 Nginx + Java(SpringBoot) 实现带权限验证的静态文件服务器,支持文件下载、PDF预览和图片预览

需要注意的是,无需权限判断的图片不建议使用此方法,大量的图片访问会增加后台服务器的处理压力。

一、实现原理

本质上是使用了X-Sendfile功能来实现,X-Sendfile 是一种将文件下载请求重定向到Web 服务器处理的机制,该Web服务器只需负责处理请求(例如权限验证),而无需执行读取文件并发送给用户的任务。

X-Sendfile可显著提高后台服务器的性能,消除了后端程序既要读文件又要处理发送的压力,尤其是处理大文件下载的情形下!

Nginx也具有此功能,但实现方式略有不同。在Nginx中,此功能称为X-Accel-Redirect

用户请求文件,权限控制时序图:

NGINX 权限控制文件预览和下载的实现原理

二、实现步骤

1. NGINX配置

1、静态文件通过file_server访问,会被设置为internal,即只能内部访问不允许外部直接访问。
2、所有静态资源请求均被重定向到Java后台,经过权限验证后才能访问。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 文件下载服务
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内部请求处理,不会暴露给请求用户。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/**
 * @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");
}

后台可配置属性:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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)的形式下载并保存到本地。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
 * @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. 下载限速

?
1
2
// 限速,单位字节,默认不限
response.setHeader("X-Accel-Limit-Rate","1024");

3. 防盗链

?
1
2
3
4
5
6
7
//判断 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 是没法做到的,因为请求交给了后台,你并不知道下载是否成功。

参考资料

  1. X-Sendfile-从Web应用程序有效地提供大型静态文件
  2. Nginx-X-Accel-Redirect
  3. Nginx -XSendfile
  4. Content-Disposition
  5. Http Content-Type

到此这篇关于NGINX 权限控制文件预览和下载的文章就介绍到这了,更多相关nginx文件预览下载内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/wxb880114/article/details/122430464

延伸 · 阅读

精彩推荐
  • NginxNginx(PHP/fastcgi)的PATH_INFO问题

    Nginx(PHP/fastcgi)的PATH_INFO问题

    PATH_INFO是一个CGI 1.1的标准,经常用来做为传参载体. 比如, 我们可以使用PATH_INFO来代替Rewrite来实现伪静态页面, 另外不少PHP框架也使用PATH_INFO来作为路由载...

    Nginx技术网2262019-10-11
  • Nginx在服务器上启用HTTPS的详细教程

    在服务器上启用HTTPS的详细教程

    这篇文章主要介绍了在服务器上启用HTTPS的详细教程,包括在AWS中生成SSL证书以及在Nginx上的相关配置等,极力推荐!需要的朋友可以参考下 ...

    goldensun6402019-10-29
  • Nginx为什么我推荐Nginx作为后端服务器代理(原因解析)

    为什么我推荐Nginx作为后端服务器代理(原因解析)

    这篇文章主要介绍了为什么我推荐Nginx作为后端服务器代理,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参...

    码农小胖哥2302020-07-23
  • Nginx在Nginx服务器中启用SSL的配置方法

    在Nginx服务器中启用SSL的配置方法

    这篇文章主要介绍了在Ningx服务器中启用SSL的配置方法,本文前提是已经在Linux系统下安装好了OpenSSL,需要的朋友可以参考下 ...

    goldensun2742019-10-31
  • Nginx分享一份nginx重启脚本

    分享一份nginx重启脚本

    nginx是超级稳定的服务器,一般不会因为超载问题而需要重启,重启的目的一般都是修改配置文件后需要加载一下 ...

    nginx教程网2752019-10-12
  • Nginx通过Nginx+Tomcat+Redis实现持久会话

    通过Nginx+Tomcat+Redis实现持久会话

    这篇文章主要介绍了通过Nginx+Tomcat+Redis实现持久会话的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下 ...

    Aubin6052019-12-11
  • NginxNginx解决403 forbidden的完整步骤

    Nginx解决403 forbidden的完整步骤

    这篇文章主要给大家介绍了关于Nginx解决403 forbidden的完整步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要...

    入门小站8022020-09-11
  • NginxNginx跨域设置Access-Control-Allow-Origin无效的解决办法

    Nginx跨域设置Access-Control-Allow-Origin无效的解决办法

    今天小编就为大家分享一篇关于Nginx跨域设置Access-Control-Allow-Origin无效的解决办法,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要...

    frank_passion13842020-01-04