From 1d2c8378f7b84521cb513967bd25517da9376fb2 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Tue, 02 Sep 2025 13:26:33 +0800
Subject: [PATCH] 文件支持防盗链配置
---
ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/filter/RefererFilter.java | 77 +++++++++++++++++++++++++
ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/FilterConfig.java | 46 +++++++++++++++
sql/ry_config_20250902.sql | 2
3 files changed, 124 insertions(+), 1 deletions(-)
diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/FilterConfig.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/FilterConfig.java
new file mode 100644
index 0000000..09136bb
--- /dev/null
+++ b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/FilterConfig.java
@@ -0,0 +1,46 @@
+package com.ruoyi.file.config;
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.servlet.DispatcherType;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import com.ruoyi.file.filter.RefererFilter;
+
+/**
+ * Filter配置
+ *
+ * @author ruoyi
+ */
+@Configuration
+public class FilterConfig
+{
+ /**
+ * 资源映射路径 前缀
+ */
+ @Value("${file.prefix}")
+ public String localFilePrefix;
+
+ @Value("${referer.allowed-domains}")
+ private String allowedDomains;
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ @Bean
+ @ConditionalOnProperty(value = "referer.enabled", havingValue = "true")
+ public FilterRegistrationBean refererFilterRegistration()
+ {
+ FilterRegistrationBean registration = new FilterRegistrationBean();
+ registration.setDispatcherTypes(DispatcherType.REQUEST);
+ registration.setFilter(new RefererFilter());
+ registration.addUrlPatterns(localFilePrefix + "/*");
+ registration.setName("refererFilter");
+ registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE);
+ Map<String, String> initParameters = new HashMap<String, String>();
+ initParameters.put("allowedDomains", allowedDomains);
+ registration.setInitParameters(initParameters);
+ return registration;
+ }
+}
diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/filter/RefererFilter.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/filter/RefererFilter.java
new file mode 100644
index 0000000..0aafbe7
--- /dev/null
+++ b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/filter/RefererFilter.java
@@ -0,0 +1,77 @@
+package com.ruoyi.file.filter;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * 防盗链过滤器
+ *
+ * @author ruoyi
+ */
+public class RefererFilter implements Filter
+{
+ /**
+ * 允许的域名列表
+ */
+ public List<String> allowedDomains;
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException
+ {
+ String domains = filterConfig.getInitParameter("allowedDomains");
+ this.allowedDomains = Arrays.asList(domains.split(","));
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws IOException, ServletException
+ {
+ HttpServletRequest req = (HttpServletRequest) request;
+ HttpServletResponse resp = (HttpServletResponse) response;
+
+ String referer = req.getHeader("Referer");
+
+ // 如果Referer为空,拒绝访问
+ if (referer == null || referer.isEmpty())
+ {
+ resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Access denied: Referer header is required");
+ return;
+ }
+
+ // 检查Referer是否在允许的域名列表中
+ boolean allowed = false;
+ for (String domain : allowedDomains)
+ {
+ if (referer.contains(domain))
+ {
+ allowed = true;
+ break;
+ }
+ }
+
+ // 根据检查结果决定是否放行
+ if (allowed)
+ {
+ chain.doFilter(request, response);
+ }
+ else
+ {
+ resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Access denied: Referer '" + referer + "' is not allowed");
+ }
+ }
+
+ @Override
+ public void destroy()
+ {
+
+ }
+}
\ No newline at end of file
diff --git a/sql/ry_config_20250224.sql b/sql/ry_config_20250902.sql
similarity index 96%
rename from sql/ry_config_20250224.sql
rename to sql/ry_config_20250902.sql
index a01ed9f..8ea4884 100644
--- a/sql/ry_config_20250224.sql
+++ b/sql/ry_config_20250902.sql
@@ -40,7 +40,7 @@
(5,'ruoyi-system-dev.yml','DEFAULT_GROUP','# spring配置\nspring:\n redis:\n host: localhost\n port: 6379\n password: \n datasource:\n druid:\n stat-view-servlet:\n enabled: true\n loginUsername: ruoyi\n loginPassword: 123456\n dynamic:\n druid:\n initial-size: 5\n min-idle: 5\n maxActive: 20\n maxWait: 60000\n connectTimeout: 30000\n socketTimeout: 60000\n timeBetweenEvictionRunsMillis: 60000\n minEvictableIdleTimeMillis: 300000\n validationQuery: SELECT 1 FROM DUAL\n testWhileIdle: true\n testOnBorrow: false\n testOnReturn: false\n poolPreparedStatements: true\n maxPoolPreparedStatementPerConnectionSize: 20\n filters: stat,slf4j\n connectionProperties: druid.stat.mergeSql\\=true;druid.stat.slowSqlMillis\\=5000\n datasource:\n # 主库数据源\n master:\n driver-class-name: com.mysql.cj.jdbc.Driver\n url: jdbc:mysql://localhost:3306/ry-cloud?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8\n username: root\n password: password\n # 从库数据源\n # slave:\n # username: \n # password: \n # url: \n # driver-class-name: \n\n# mybatis配置\nmybatis:\n # 搜索指定包别名\n typeAliasesPackage: com.ruoyi.system\n # 配置mapper的扫描,找到所有的mapper.xml映射文件\n mapperLocations: classpath:mapper/**/*.xml\n\n# springdoc配置\nspringdoc:\n gatewayUrl: http://localhost:8080/${spring.application.name}\n api-docs:\n # 是否开启接口文档\n enabled: true\n info:\n # 标题\n title: \'系统模块接口文档\'\n # 描述\n description: \'系统模块接口描述\'\n # 作者信息\n contact:\n name: RuoYi\n url: https://ruoyi.vip\n','786c7daf4543411fc65c3e48dfb15243','2020-11-20 00:00:00','2024-09-02 12:14:33','nacos','0:0:0:0:0:0:0:1','','','系统模块','null','null','yaml','',''),
(6,'ruoyi-gen-dev.yml','DEFAULT_GROUP','# spring配置\nspring:\n redis:\n host: localhost\n port: 6379\n password: \n datasource:\n driver-class-name: com.mysql.cj.jdbc.Driver\n url: jdbc:mysql://localhost:3306/ry-cloud?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8\n username: root\n password: password\n\n# mybatis配置\nmybatis:\n # 搜索指定包别名\n typeAliasesPackage: com.ruoyi.gen.domain\n # 配置mapper的扫描,找到所有的mapper.xml映射文件\n mapperLocations: classpath:mapper/**/*.xml\n\n# springdoc配置\nspringdoc:\n gatewayUrl: http://localhost:8080/${spring.application.name}\n api-docs:\n # 是否开启接口文档\n enabled: true\n info:\n # 标题\n title: \'代码生成接口文档\'\n # 描述\n description: \'代码生成接口描述\'\n # 作者信息\n contact:\n name: RuoYi\n url: https://ruoyi.vip\n\n# 代码生成\ngen:\n # 作者\n author: ruoyi\n # 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool\n packageName: com.ruoyi.system\n # 自动去除表前缀,默认是false\n autoRemovePre: false\n # 表前缀(生成类名不会包含表前缀,多个用逗号分隔)\n tablePrefix: sys_\n # 是否允许生成文件覆盖到本地(自定义路径),默认不允许\n allowOverwrite: false','43d807aa0a4accbb193b6dc7e38ac8a3','2020-11-20 00:00:00','2024-12-25 08:29:33','nacos','0:0:0:0:0:0:0:1','','','代码生成','null','null','yaml','',''),
(7,'ruoyi-job-dev.yml','DEFAULT_GROUP','# spring配置\nspring:\n redis:\n host: localhost\n port: 6379\n password: \n datasource:\n driver-class-name: com.mysql.cj.jdbc.Driver\n url: jdbc:mysql://localhost:3306/ry-cloud?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8\n username: root\n password: password\n\n# mybatis配置\nmybatis:\n # 搜索指定包别名\n typeAliasesPackage: com.ruoyi.job.domain\n # 配置mapper的扫描,找到所有的mapper.xml映射文件\n mapperLocations: classpath:mapper/**/*.xml\n\n# springdoc配置\nspringdoc:\n gatewayUrl: http://localhost:8080/${spring.application.name}\n api-docs:\n # 是否开启接口文档\n enabled: true\n info:\n # 标题\n title: \'定时任务接口文档\'\n # 描述\n description: \'定时任务接口描述\'\n # 作者信息\n contact:\n name: RuoYi\n url: https://ruoyi.vip\n','f78483f845777335b9ed4a9f84758848','2020-11-20 00:00:00','2024-09-02 12:14:56','nacos','0:0:0:0:0:0:0:1','','','定时任务','null','null','yaml','',''),
-(8,'ruoyi-file-dev.yml','DEFAULT_GROUP','# 本地文件上传 \r\nfile:\r\n domain: http://127.0.0.1:9300\r\n path: D:/ruoyi/uploadPath\r\n prefix: /statics\r\n\r\n# FastDFS配置\r\nfdfs:\r\n domain: http://8.129.231.12\r\n soTimeout: 3000\r\n connectTimeout: 2000\r\n trackerList: 8.129.231.12:22122\r\n\r\n# Minio配置\r\nminio:\r\n url: http://8.129.231.12:9000\r\n accessKey: minioadmin\r\n secretKey: minioadmin\r\n bucketName: test','5382b93f3d8059d6068c0501fdd41195','2020-11-20 00:00:00','2020-12-21 21:01:59',NULL,'0:0:0:0:0:0:0:1','','','文件服务','null','null','yaml',NULL,''),
+(8,'ruoyi-file-dev.yml','DEFAULT_GROUP','# 本地文件上传 \nfile:\n domain: http://127.0.0.1:9300\n path: D:/ruoyi/uploadPath\n prefix: /statics\n\n# FastDFS配置\nfdfs:\n domain: http://127.0.0.1\n soTimeout: 3000\n connectTimeout: 2000\n trackerList: 127.0.0.1:22122\n\n# Minio配置\nminio:\n url: http://127.0.0.1:9000\n accessKey: minioadmin\n secretKey: minioadmin\n bucketName: test\n\n # 防盗链配置\nreferer:\n # 防盗链开关\n enabled: false\n # 允许的域名列表\n allowed-domains: localhost,127.0.0.1,ruoyi.vip,www.ruoyi.vip\n','095791a04211d6e3d294359b21357394','2020-11-20 00:00:00','2025-09-02 05:10:11','nacos','0:0:0:0:0:0:0:1','','','文件服务','null','null','yaml','',''),
(9,'sentinel-ruoyi-gateway','DEFAULT_GROUP','[\r\n {\r\n \"resource\": \"ruoyi-auth\",\r\n \"count\": 500,\r\n \"grade\": 1,\r\n \"limitApp\": \"default\",\r\n \"strategy\": 0,\r\n \"controlBehavior\": 0\r\n },\r\n {\r\n \"resource\": \"ruoyi-system\",\r\n \"count\": 1000,\r\n \"grade\": 1,\r\n \"limitApp\": \"default\",\r\n \"strategy\": 0,\r\n \"controlBehavior\": 0\r\n },\r\n {\r\n \"resource\": \"ruoyi-gen\",\r\n \"count\": 200,\r\n \"grade\": 1,\r\n \"limitApp\": \"default\",\r\n \"strategy\": 0,\r\n \"controlBehavior\": 0\r\n },\r\n {\r\n \"resource\": \"ruoyi-job\",\r\n \"count\": 300,\r\n \"grade\": 1,\r\n \"limitApp\": \"default\",\r\n \"strategy\": 0,\r\n \"controlBehavior\": 0\r\n }\r\n]','9f3a3069261598f74220bc47958ec252','2020-11-20 00:00:00','2020-11-20 00:00:00',NULL,'0:0:0:0:0:0:0:1','','','限流策略','null','null','json',NULL,'');
--
Gitblit v1.9.3