Nginx访问FTP服务器文件的时效性/安全校验

背景

FTP文件服务器在我们日常开发中经常使用,在项目中我们经常把FTP文件下载到内存中,然后转为base64给前端进行展示。如果excel中也需要导出图片,数据量大的情况下会直接返回一个后端的开放接口地址,然后在项目中对接口的参数进行鉴权,或者实效性检验等,最后从FTP下载图片用流的方式传到浏览器中。

但是这种方式会加大内存的消耗,所有的文件相关的都在内存中下载回传给前端;报表下载的数据量很大的情况下服务很容易拖垮。所以就设想通过两层nginx反向代理的方式是否可以满足文件的直接访问。

假设FTP文件服务器的照片存放地址为:/upload/signature

传统实现

首先我们在下载excel的时候需要组装一个url,如下所示的get请求就是一个对外开放无需权限的接口,真实情况下会对realFilePath进行加密组装,里面放一些timestamp或者redis的key来验证实效性、安全性等。

	  @GetMapping("/signatureImage/{path}")
    public void signatureImage(@PathVariable("path") String realFilePath, HttpServletResponse response) throws IOException {
        //realFilePath = "/20231206/qhyu.png"
        String fileName = "qhyu.png"; //可以切割获取。
        String path = "/upload/signature"; // 固定的存放路径
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        try (Ftp ftp = new Ftp("Ftp_address", "Ftp_port", "username", "password")) {
            ftp.download(path+realFilePath, fileName, outputStream);
        } catch (Exception e) {
            log.error("FTP文件下载出错:{}", e.getMessage());
            throw new QhyuException(MessageCode.FILE_DOENLOAD_ERROR.getCode());
        }
        // 将内存中的文件内容转换为输入流
        InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
        // 设置响应的内容类型为图片格式
        String contentType = MediaType.IMAGE_PNG_VALUE; // 假设为PNG格式
        response.setContentType(contentType);
        org.apache.commons.io.IOUtils.copy(inputStream, response.getOutputStream());
        response.flushBuffer();
        // 关闭内存流和FTP连接
        inputStream.close();
        outputStream.close();
    }

Nginx实现

要通过Nginx实现的话,基本上网上的方案都是让使用lua。虽然可以但是没必要。因为我从官网上找到了解决方案,如下所示。
在这里插入图片描述

提供一下proxy相关参数的含义:

  1. proxy_set_header Host $host;
    此参数设置了将客户端请求中的Host头部信息传递给代理服务器。$host变量表示客户端请求中的主机名。
  2. proxy_intercept_errors on;
    当启用此参数时,代理服务器会拦截后端服务器返回的错误响应,并将其作为代理服务器的响应返回给客户端。这允许代理服务器处理后端服务器的错误响应,并可以进行自定义的错误处理。
  3. proxy_set_header X-Real-IP $remote_addr;
    此参数设置了将客户端的真实IP地址传递给代理服务器。$remote_addr变量表示客户端的IP地址。
  4. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    此参数设置了将客户端的IP地址添加到X-Forwarded-For头部信息中。$proxy_add_x_forwarded_for变量表示将客户端IP地址添加到现有的X-Forwarded-For头部信息中。
  5. proxy_buffering off;
    当启用此参数时,禁用代理缓冲。代理缓冲可以在接收完整的响应后再将其发送给客户端,以提高性能和效率。禁用缓冲意味着代理服务器会立即将收到的数据发送给客户端,适用于需要实时数据传输的场景。

下面就是我的nginx配置:

    server {
        listen       10086;
        charset utf-8;
        access_log      /var/log/nginx/qhyu/qhyu_access.log;
        error_log      /var/log/nginx/qhyu/qhyu_error.log;
    
   location /verify {
        proxy_pass http://host:port/api/signatureImage/validate?realFilePath=$arg_realFilePath&signature=$arg_signature;
        proxy_set_header Host $host;
        proxy_intercept_errors on;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_buffering off;
        error_page 418 = @custom_redirect;
        error_page 420 = @custom_error;
     }

      location @custom_error{
        default_type application/json;
        return 200 'error image';
      }

      location @custom_redirect {
        rewrite ^ /signature/$arg_realFilePath last;
      }

      location /signature {
        alias /upload/signature/;
      }
}
}

然后就是编写了一个接口,也就是在调用的时候可以访问/verify接口带上参数,就会跳转到这个接口进行校验,如果返回的http状态码是418说明校验通过,如果返回的是420说明校验失败。

@GetMapping("/signatureImage/validate")
    public Object signatureValidate(String realFilePath,String signature,HttpServletResponse httpServletResponse){
        String redisKey = AesEncryptUtil.decryption(signature);
        if (StrUtil.isBlank(redisKey)){
            httpServletResponse.setStatus(420);
            return RenderResult.success();
        }
        Object value = redisService.get(redisKey);
        if (value == null) {
            httpServletResponse.setStatus(420);
            return RenderResult.success();
        }
        List<String> signatureUrls = JSON.parseArray(JSON.toJSONString(value), String.class);
        if (signatureUrls == null || signatureUrls.isEmpty()){
            httpServletResponse.setStatus(420);
            return RenderResult.success();
        }
        if (!signatureUrls.contains(realFilePath)){
            httpServletResponse.setStatus(420);
            return RenderResult.success();
        }
        // greater than or equal to 300 should be passed to a client or be intercepted and redirected to nginx
        // for processing with the error_page directive
        // http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_intercept_errors
        httpServletResponse.setStatus(418);
        return RenderResult.success();
    }

分析结果

nginx的实现方式在校验失败的时候页面返回error image,跳转的是420 error_page;成功的时候会访问FTP文件服务器的路径,反正图片到页面展示。在实际的开发过程中,外层可能还会有一个nginx反向代理,本文主要讲解了一下如何使用这个方式对访问的文件进行鉴权。

这样做的好处就是不需要每个文件都下载到内存然后使用流的方式传输,直接访问的方式减少了后端服务的压力,并且像头像、签名这种可能访问频繁的接口使用这种方式来处理是很棒的一种方式。

主要的思路就是拿到proxy_pass的返回信息,如果使用lua的话可以获取到我们返回的body内容,但是不使用lua的时候我们可以迂回处理,使用status code也一样可以达到目的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/237278.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Golang 使用 Template 引擎构建漂亮的邮件内容并且完成邮件发送

背景 邮件是常见的触达用户的途径&#xff0c;本文详细介绍基于 golang 的模版引擎构建漂亮的邮件内容&#xff0c;并且发送给模板用户。 思路 go 内置了 html/template 模块&#xff0c;类似 ejs 模块引擎。利用 template 能力可以将变量动态的注入到HTML字符串中&#xff…

迅为RK3568开发板使用OpenCV处理图像(颜色转换)

1 颜色转换 本小节代码在配套资料“iTOP-3568 开发板\03_【iTOP-RK3568 开发板】指南教程 \04_OpenCV 开发配套资料\05”目录下&#xff0c;如下图所示&#xff1a; cv2.cvtColor()函数功能&#xff1a; 将一幅图像从一个色彩空间转换到另一个色彩空间。 函数原型&#xff…

5G CPE可代替宽带,解决断网问题

最近某运营商就玩起了套餐&#xff0c;断用户的网。 老百姓对宽带半知不解&#xff0c;网络断了没法上网&#xff0c;很着急。因为相信运营商&#xff0c;维修人员怎么说&#xff0c;老百姓就怎么办呗&#xff0c;直到最后才发现自己上当&#xff0c;但钱都给了。 截至2023年9月…

Django讲课笔记02:Django环境搭建

文章目录 一、学习目标二、相关概念&#xff08;一&#xff09;Python&#xff08;二&#xff09;Django 三、环境搭建&#xff08;一&#xff09;安装Python1. 从官方网站下载最新版本的Python2. 运行安装程序并按照安装向导进行操作3. 勾选添加到路径复选框4. 完成安装过程5.…

公共模块无法实例化Elasticsearch的interface类

public interface EsLogDao extends ElasticsearchRepository<EsLog, String> {}Data NoArgsConstructor Document(indexName "my_log") public class EsLog implements Serializable {Idprivate String id; } 出现的错误 解决方案&#xff0c;在公共模块增加…

centos7安全防护_CPU占用率超过百分之300_centos7.4中毒CPU百分之百_清理毒源---Linux工作笔记068

执行top命令的时候看到有个进程: sshd占用cpu百分之300多...而且就算是kill -9 杀掉进程以后,进程又会自动启动 ll /proc/7298 我们执行这个命令,可以看到有个/var/tmp/sshd的文件 我们进入cd /var/tmp 然后我们执行 rm -rf sshd删除这个文件,然后我们再去top可以看到 cpu就…

多线程(初阶九:线程池)

目录 一、线程池的由来 二、线程池的简单介绍 1、ThreadPoolExecutor类 &#xff08;1&#xff09;核心线程数和最大线程数&#xff1a; &#xff08;2&#xff09;保持存活时间和存活时间的单位 &#xff08;3&#xff09;放任务的队列 &#xff08;4&#xff09;线程工…

我的网站服务器被入侵了该怎么办?

最近有用户咨询到德迅云安全&#xff0c;说自己再用的网站服务器遇到了入侵情况&#xff0c;询问该怎么处理入侵问题&#xff0c;有什么安全方案可以解决服务器被入侵的问题。下面&#xff0c;我们就来简单讲下服务器遇到入侵了&#xff0c;该从哪方面入手处理&#xff0c;在预…

华清远见嵌入式学习——QT——作业3

作业要求: 代码效果图&#xff1a; 登录成功并跳转页面 登录失败 关闭 代码&#xff1a; 第一页面头文件&#xff1a; #ifndef LOGIN_H #define LOGIN_H#include <QWidget> #include <QMessageBox>QT_BEGIN_NAMESPACE namespace Ui { class Login; } QT_END_NAME…

Hbase2.5.5分布式部署安装记录

文章目录 1 环境准备1.1 节点部署情况1.2 安装说明 2 Hbase安装过程Step1&#xff1a;Step2:Step3:Step4&#xff1a; 3 Web UI检查状态并测试3.1 Web UI3.2 创建测试命名空间 1 环境准备 1.1 节点部署情况 Hadoop11&#xff1a;Hadoop3.1.4 、 zookeeper3.4.6、jdk8 Hadoop1…

OpenCV | sift函数使用——得到特征点

scale invariant feature transform (sift) 图像尺度空间 在一定的范围内&#xff0c;无论物体是大还是小&#xff0c;人眼都可以分辨出来&#xff0c;然而计算机要有相同的能力却很难&#xff0c;所以要让机器能够对物体在不同尺度下有一个统一的认知&#xff0c; 就需要考虑…

分页设计(平时在表下面的栏框,有首页 | 上一页 | 下一页 | 尾页),下面代码带你实现

分页设计的本质就是&#xff0c;分页查询&#xff0c;就是SQL语句当中的(select * from ? limit ? , &#xff1f;&#xff09;,这里第一个&#xff1f;是所分页的那张表 &#xff0c;第二个&#xff1f;从哪条开始&#xff0c;第三个&#xff1f;是在页面上想让这张表出现几…

Linux系统vim,gcc,g++工具使用及环境配置,动静态库的概念及使用

Linux系统vim&#xff0c;gcc&#xff0c;g工具使用及环境配置&#xff0c;动静态库的概念及使用 1. Linux编辑器-vim的使用1.1 vim的基本概念1.2vim的基本操作1.3vim正常模式命令集1.4vim末端模式命令集1.5简单的vim配置 2.Linux编译器-gcc/g的使用2.1 准备阶段2.2gcc的使用2.…

Redis持久化机制 RDB 和 AOF 的选择

目录 一、Redis 的持久化 二、Redis 的持久化方式 Redis 提供了两种持久化的方式&#xff1a; RDB 介绍 RDB 的触发方式&#xff1a; AOF介绍 三、RDB 和 AOF 的选择 RDB 和 AOF 对比 1. 数据格式&#xff1a; 2. 恢复速度&#xff1a; 3. 数据丢失 4. 文件大小&…

这七款网工在线画拓扑工具,绝了!

你们好&#xff0c;我的网工朋友。 画拓扑图&#xff0c;绝对是网络工程师的基操。 上次给你来了篇手把手教你绘制拓扑图的好文&#xff0c;还没看过的先去看啊&#xff1a;《网络拓扑图怎么画最好&#xff1f;》。 关于画拓扑的工具&#xff0c;那就多了&#xff0c;直接用…

什么是 web 组态?web 组态与传统组态的区别是什么?

组态软件是一种用于控制和监控各种设备的软件&#xff0c;也是指在自动控制系统监控层一级的软件平台和开发环境。这类软件实际上也是一种通过灵活的组态方式&#xff0c;为用户提供快速构建工业自动控制系统监控功能的、通用层次的软件工具。通常用于工业控制&#xff0c;自动…

c++时间转换

获取当前时间字符串 std::string GetFormatTime() {time_t currentTime;time(&currentTime);tm* t_tm localtime(&currentTime);char formatTime[64] {0};snprintf(formatTime, 64, "%04d-%02d-%02d %02d:%02d:%02d", t_tm->tm_year 1900,t_tm->tm…

Python从入门到精通五:Python函数

函数介绍 学习目标&#xff1a; 快速体验函数的使用了解函数的作用 函数&#xff1a;是组织好的&#xff0c;可重复使用的&#xff0c;用来实现特定功能的代码段。 我们使用过的&#xff1a;input()、print()、str()、int()等都是Python的内置函数。 为什么要学习、使用函…

2023年团体程序设计天梯赛——总决赛题

F-L1-1 最好的文档 有一位软件工程师说过一句很有道理的话&#xff1a;“Good code is its own best documentation.”&#xff08;好代码本身就是最好的文档&#xff09;。本题就请你直接在屏幕上输出这句话。 输入格式&#xff1a; 本题没有输入。 输出格式&#xff1a; 在一…

使用 PyTorch FSDP 微调 Llama 2 70B

通过本文&#xff0c;你将了解如何使用 PyTorch FSDP 及相关最佳实践微调 Llama 2 70B。在此过程中&#xff0c;我们主要会用到 Hugging Face Transformers、Accelerate 和 TRL 库。我们还将展示如何在 SLURM 中使用 Accelerate。 完全分片数据并行 (Fully Sharded Data Paral…