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_errorshttpServletResponse.setStatus(418);return RenderResult.success();}

分析结果

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

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网站使用CDN后无法获取用户真实IP的解决方法

宝塔或Nginx环境 如果你使用的宝塔或Nginx&#xff0c;可以在宝塔面板或Nginx中&#xff0c;找到配置文件增加如下代码后&#xff0c;重载配置或者重启 Nginx 即可&#xff1a; #CDN获取真实ip set_real_ip_from 0.0.0.0/0; real_ip_header X-Forwarded-For; PHP语言函数方法…

Java刷题篇——LeetCode118. 杨辉三角

1.题目描述 给定一个非负整数numRows&#xff0c;生成杨辉三角的前numRows行。 在杨辉三角中&#xff0c;每个数是它左上方和右上方的数的和。 示例1 输入&#xff1a;numRows 5 输出&#xff1a;[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1] 示例2 输入&#xff1a;numRows 1…

安装DevEco Studio

下载 首先进入鸿蒙开发者官网&#xff0c;顶部导航栏选择开发->DevEco Studio 根据操作系统下载不同版本&#xff0c;其中Mac(X86)为英特尔芯片&#xff0c;Mac(ARM)为M芯片。 安装 下载完毕后&#xff0c;开始安装。 点击Agree 首次使用&#xff0c;请选择Do not impor…

Linux篇之在Centos环境下搭建Nvidia显卡驱动

一、前提条件 1、首先确认内核版本和发行版本&#xff0c;再确认显卡型号 uname -a // Linux localhost.localdomain 4.18.0-408.el8.x86_64 #1 SMP Mon Jul 18 17:42:52 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux1.2 cat /etc/redhat-release // CentOS Stream release 81.3…

使用Git进行版本控制

参考&#xff1a;《Python编程从入门到实践》 前言1、安装、配置 Git1.1 在Linux系统中安装Git1.2 在OS X系统中安装Git1.3 在Windows系统中安装Git1.4 配置Git 2、创建项目3、忽略文件4、初始化仓库5、检查状态6、将文件加入到仓库中7、执行提交8、查看提交历史9、第二次提交1…

Seata配置

参考教程 seata 分布式事务的环境搭建与使用 Seata 1.4.0 nacos配置和使用&#xff0c;超详细 Seata 1.4.2 的安装 Nacos的配置和使用 官网下载地址 本文以v1.4.1为例 1.数据库及表的创建 创建seata数据库&#xff0c;创建以下表&#xff08;右键连接-》新建数据库seata-》…

2023.12.6 关于 Spring Boot 事务的基本概念

目录 事务基本概念 前置准备 Spring Boot 事务使用 编程式事务 声明式事务 Transactional 注解参数说明 Transational 对异常的处理 解决方案一 解决方案二 Transactional 的工作原理 面试题 Spring Boot 事务失效的场景有那些&#xff1f; 事务基本概念 事务指一…

【AI神器】CodeGeeX智能编程助手

目录 1.CodeGeeX介绍2.IDEA插件安装3.助手功能3.1 代码分析&#xff08;/explain&#xff09;3.2 代码自动补全3.3 AI优化代码3.4 代码添加注释&#xff08;/comment&#xff09;3.5 AI添加文档3.6 单元测试生成&#xff08;/tests&#xff09;3.7 bug查找修正&#xff08;/fix…

[OpenWrt]RAX3000一根线实现上网和看IPTV

背景&#xff1a; 1.我家电信宽带IPTV 2.入户光猫&#xff0c;桥接模式 3.光猫划分vlan&#xff0c;将上网信号IPTV信号&#xff0c;通过lan口&#xff08;问客服要光猫超级管理员密码&#xff0c;具体教程需要自行查阅&#xff0c;关键是要设置iptv在客户侧的vlan id&#…

Maven基础

目录 Maven坐标 坐标简介 主要组成 Maven依赖管理 配置依赖 依赖简介 配置依赖 依赖传递 依赖传递简介 排除依赖 依赖范围 生命周期 生命周期简介 执行指定生命周期 Maven坐标 坐标简介 Maven中的坐标是资源的唯一标识&#xff0c;通过该坐标可以唯一定位资…

Yolov5双目测距-双目相机计数及测距教程(附代码)

引言 在计算机视觉领域&#xff0c;Yolov5-Binocular相机距离计数及测距是一个引人注目的研究方向。本教程将为小白用户提供一个简明扼要的学习指南&#xff0c;涵盖了关键步骤&#xff0c;包括标定、公示推倒以及重要的代码片段。 第一步&#xff1a;环境搭建 首先&#x…

cpp:1:10: fatal error: opencv2/core.hpp: 没有那个文件或目录

前言&#xff1a; 我按照官网方法安装了opencv&#xff0c;运行的也是官网的测试代码&#xff1a; #include <opencv2/core.hpp> #include <opencv2/highgui.hpp> using namespace cv; int main() {printf("hello world")return 0; } 半解决&#xff…

07用户行为日志数据采集

用户行为数据由Flume从Kafka直接同步到HDFS&#xff0c;由于离线数仓采用Hive的分区表按天统计&#xff0c;所以目标路径要包含一层日期。具体数据流向如下图所示。 按照规划&#xff0c;该Flume需将Kafka中topic_log的数据发往HDFS。并且对每天产生的用户行为日志进行区分&am…

java-sec-code的xss

java-sec-code 用于学习java漏洞代码 环境部署 直接在idea中使用git 运行即可 RequestMapping("/reflect") ResponseBody public static String reflect(String xss) {return xss;}当用户访问到/reflect URL地址时&#xff0c;程序会自动调用reflect方法&#xff0c…

JS对象笔记

对象声明 对象也只是一种数据类型/字面值。写对象这个字面值有两种写法&#xff0c;一种是普通的对象&#xff0c;这种对象用new 构造函数&#xff08;&#xff09;&#xff0c;另一种是JS内特有的json对象。这个对象是直接{}就代表对象。且也是在堆内。 对象的构成 无论是上…

Blender学习--制作带骨骼动画的机器人

1. 首先创建一个机器人模型 时间关系&#xff0c;这部分步骤有时间补充 2. 然后为机器人创建一副骨架 时间关系&#xff0c;这部分步骤有时间补充 3.骨骼绑定 切换到物体模式&#xff0c;选中机器人头部&#xff0c;Shift选中骨骼&#xff0c;切换到姿态模式&#xff0c;&am…

《Easy3d+Qt+VTK》学习

《Easy3dQtVTK》学习-1、编译与配置 一、编译二、配置注 一、编译 1、 资源下载&#xff1a;easy3d giuhub 2、解压缩 3、用qt打开CMakeLists.txt即可 4、点击项目&#xff0c;选择debug或者release&#xff0c;图中3处可自行选择&#xff0c;因为我的qt版本是6&#xff0c…

【TC3xx】GETH

目录 一、RGMII 二、SMI接口 三、TC3xx MCAL 3.1 MCU 3.2 Port 3.3 DMA 3.4 中断配置 3.5 ETH 3.6 集成 一、RGMII TC3xx支持MII/RMII/RGMII三种以太网数据通信接口。其中RGMII经常用于MAC和MAC之间&#xff0c;或MAC与PHY之间的通信&#xff0c;RGMII的带宽可以是10M…

ViTDet论文笔记

arxiv&#xff1a;https://arxiv.org/abs/2203.16527 GitHub&#xff1a;https://github.com/ViTAE-Transformer/ViTDet 摘要 本文提出使用plain&#xff0c;non-hierarchical视觉transformer作为目标检测的主干网络。通过这种设计可以使得ViT结构模型不需要再重新设计一个分…

51单片机控制1602LCD显示屏输出两行文字一

51单片机控制1602LCD显示屏输出两行文字一 1.概述 这篇文章介绍1602型号显示屏的基础知识&#xff0c;以及使用单片机控制它输出两行内容。 2.1602基础知识 1602 液晶显示模块是一种通用的工业液晶显示模块&#xff0c;专门用来显示字母、数字、符号等的点阵型液晶显示模块…