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

news2024/12/23 23:31:24

背景

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也一样可以达到目的。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微信小程序 ios 手机底部安全区适配

在开发微信小程序中&#xff0c;遇到 IOS 全面屏手机&#xff0c;底部小黑条会遮挡页面按钮或内容&#xff0c;因此需要做适配处理。 解决方案 通过 wx.getSystemInfo() 获取手机系统信息&#xff0c;需要拿到&#xff1a;screenHeight&#xff08;屏幕高度&#xff09;&#…

持续集成交付CICD:GitLabCI上传Nexus制品

目录 一、实验 1.GitLabCI上传Nexus制品 2.优化GitLabCI&#xff08;引用系统变量&#xff09; 3.添加if条件判断项目类型 4.优化GitLabCI&#xff08;模板类&#xff09; 二、问题 1.GitLabCI获取jar文件失败 2. GitLabCI获取流水线项目命名空间失败 3.GItLab Packag…

学习pytorch19 pytorch使用GPU训练2

pytorch使用GPU训练2 第二种使用gpu方式核心代码代码 macbook pro m1/m2 用mps &#xff0c; 是苹果arm芯片的gpu 第二种使用gpu方式核心代码 # 设置设备 device torch.device(cpu) # 使用cpu device torch.device(cuda) # 单台gpu device torch.device(cuda:0) # 使…

基于大语言模型的复杂任务认知推理算法CogTree

近日&#xff0c;阿里云人工智能平台PAI与华东师范大学张伟教授团队合作在自然语言处理顶级会议EMNLP2023上发表了基于认知理论所衍生的CogTree认知树生成式语言模型。通过两个系统&#xff1a;直觉系统和反思系统来模仿人类产生认知的过程。直觉系统负责产生原始问题的多个分解…

打包CSS

接上一个打包HTML继续进行CSS的打包 1.在之前的文件夹里的src文件夹创建一个css文件 2.在浏览器打开webpack——>中文文档——>指南——>管理资源——>加载CSS 3.复制第一句代码到终端 4.复制下图代码到webpack.config.js脚本的plugins&#xff1a;[.....]内容下…

计算机循环神经网络(RNN)

计算机循环神经网络&#xff08;RNN&#xff09; 一、引言 循环神经网络&#xff08;RNN&#xff09;是一种常见的深度学习模型&#xff0c;适用于处理序列数据&#xff0c;如文本、语音、时间序列等。RNN通过捕捉序列数据中的时间依赖关系和上下文信息&#xff0c;能够解决很…

网络编程_网络编程三要素,TCP协议,UDP协议

网络编程 文章目录 网络编程1 网络编程三要素1.1 IP地址1.1.1 IP地址分为两大类1.1.2 DOS常用命令1.1.3 特殊IP地址 1.2 InetAddress类_表示IP地址的类1.2.1 相关方法1.2.2 示例 1.3 端口和协议1.3.1 端口与端口号1.3.2 协议1.3.3 UDP协议1.3.4 TCP协议 2 UDP通信程序2.1 UDP发…

Leetcode 1631. 最小体力消耗路径

一、题目 1、题目描述 你准备参加一场远足活动。给你一个二维 rows x columns 的地图 heights &#xff0c;其中 heights[row][col] 表示格子 (row, col) 的高度。一开始你在最左上角的格子 (0, 0) &#xff0c;且你希望去最右下角的格子 (rows-1, columns-1) &#xff08;注意…

启动cad显示丢失mfc140u.dll怎么办?mfc140u.dll丢失有效解决方法分享

在CAD软件或其他软件中&#xff0c;有时候会出现由于找不到mfc140u.dll文件而无法执行代码的错误提示。这个问题可能是由于多种原因引起的&#xff0c;例如文件损坏、缺失或被病毒感染等。下面将介绍五个常见的解决方法&#xff0c;并解释mfc140u.dll丢失的原因以及该文件对CAD…

【BI】FineBI功能学习路径-20231211

FineBI功能学习路径 https://help.fanruan.com/finebi/doc-view-1757.html 编辑数据概述 1.1 调整数据结构 1.2 简化数据 2.1上下合并 2.2其他表添加列 2.3左右合并 新增分析指标 函数参考 https://help.fanruan.com/finereport/doc-view-1897.html 数值函数 日期函数 文…

数据结构与算法-Rust 版读书笔记-2线性数据结构-栈

数据结构与算法-Rust 版读书笔记-2线性数据结构-栈 一、线性数据结构概念 数组、栈、队列、双端队列、链表这类数据结构都是保存数据的容器&#xff0c;数据项之间的顺序由添加或删除时的顺序决定&#xff0c;数据项一旦被添加&#xff0c;其相对于前后元素就会一直保持位置不…

目标检测——R-FCN算法解读

论文&#xff1a;R-FCN: Object Detection via Region-based Fully Convolutional Networks 作者&#xff1a;Jifeng Dai, Yi Li, Kaiming He and Jian Sun 链接&#xff1a;https://arxiv.org/pdf/1605.06409v2.pdf 代码&#xff1a;https://github.com/daijifeng001/r-fcn 文…

【开源】基于Vue和SpringBoot的森林火灾预警系统

项目编号&#xff1a; S 019 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S019&#xff0c;文末获取源码。} 项目编号&#xff1a;S019&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 系统基础模块2.3 烟…

CodeGeeX发布HBuilderX插件,助力VUE开发效率提升

北京时间2023年12月8日&#xff0c;CodeGeeX正式发布了适配国产IDE平台HBuilderX的插件。这款插件的推出&#xff0c;使得使用HBuilderX作为开发环境的程序员可以在IDE和AI辅助编程工具之间做出选择。 CodeGeeX&#xff1a;基于大模型的AI智能编程助理 CodeGeeX是一款基于大模…

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…

【JavaWeb学习专栏 | CSS篇】css简单介绍 css常用选择器集锦

个人主页&#xff1a;[兜里有颗棉花糖(https://xiaofeizhu.blog.csdn.net/) 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【JavaWeb学习专栏】【Java系列】 希望本文内容可以帮助到大家&#xff0c;一起加油吧&#xff01;…

IP与以太网的转发操作

TCP模块在执行连接、收发、断开等各阶段操作时&#xff0c;都需要委托IP模块将数据封装成包发送给通信对象。 网络中有路由器和集线器两种不同的转发设备&#xff0c;它们在传输网络包时有着各自的分工。 (1)路由器根据目标地址判断下一个路由器的位置 (2)集线器在子网中将网…

Redis为什么是单线程的?

Redis为什么是单线程的&#xff1f; 1.代码更清晰&#xff0c;处理逻辑更简单&#xff1b; 不2.用考虑各种锁的问题&#xff0c;不存在加锁和释放锁的操作&#xff0c;没有因为可能出现死锁而导致的性能问题&#xff1b; 3.不存在多线程切换而消耗CPU&#xff1b; 4.无法发挥多…

2023年医疗器械行业分析(京东医疗器械运营数据分析):10月销额增长53%

随着我国整体实力的增强、国民生活水平的提高、人口老龄化、医疗保障体系不断完善等因素的驱动&#xff0c;我国的医疗器械市场增长迅速。 根据鲸参谋电商数据分析平台的相关数据显示&#xff0c;今年10月份&#xff0c;京东平台上医疗器械市场的销量将近1200万&#xff0c;环比…

IDE代码编辑器:CLion 2023.3(WinMac)中文激活版

CLion 2023是一款由JetBrains公司为C/C编程设计的跨平台集成开发环境&#xff08;IDE&#xff09;。它集成了丰富的功能和工具&#xff0c;旨在帮助开发人员更高效地进行C/C编程和调试。 以下是这款软件的一些主要特点和功能&#xff1a; 高效的编程体验&#xff1a;为Mac用户提…