Compare commits
2 Commits
63db53eda8
...
9f613a2d22
| Author | SHA1 | Date |
|---|---|---|
|
|
9f613a2d22 | |
|
|
acad3beb85 |
|
|
@ -5,6 +5,7 @@ import org.springframework.boot.CommandLineRunner;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||||
|
import org.springframework.boot.web.servlet.ServletComponentScan;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
|
@ -14,6 +15,7 @@ import javax.annotation.Resource;
|
||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })
|
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })
|
||||||
|
|
||||||
public class SgzbGatewayApplication implements CommandLineRunner {
|
public class SgzbGatewayApplication implements CommandLineRunner {
|
||||||
public static void main(String[] args)
|
public static void main(String[] args)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,116 @@
|
||||||
|
package com.bonus.sgzb.gateway.filter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 30791
|
||||||
|
* @version 1.0
|
||||||
|
* Create by 2025/10/22 10:41
|
||||||
|
*/
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||||
|
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class SecurityHeaderFilter implements GlobalFilter, Ordered {
|
||||||
|
|
||||||
|
// 定义需要添加安全头的页面路径
|
||||||
|
private static final List<String> PROTECTED_PATH_PREFIXES = Arrays.asList(
|
||||||
|
"/login", "/admin", "/PMA", "/html", "/sitemap.xml",
|
||||||
|
"/db", "/dbadmin", "/myadmin", "/mysql", "/mysqladmin",
|
||||||
|
"/phpMyAdmin", "/phpMyAdmin2"
|
||||||
|
);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
||||||
|
ServerHttpRequest request = exchange.getRequest();
|
||||||
|
ServerHttpResponse response = exchange.getResponse();
|
||||||
|
String path = request.getPath().value();
|
||||||
|
String method = request.getMethod().name();
|
||||||
|
|
||||||
|
log.debug("SecurityHeaderFilter 处理请求: {} {}", method, path);
|
||||||
|
|
||||||
|
// 获取响应头
|
||||||
|
HttpHeaders headers = response.getHeaders();
|
||||||
|
|
||||||
|
// 检查是否为受保护的路径
|
||||||
|
boolean isProtectedPage = isProtectedPath(path);
|
||||||
|
|
||||||
|
|
||||||
|
// 设置 Referrer-Policy(所有请求都应用)
|
||||||
|
headers.set("Referrer-Policy", "strict-origin-when-cross-origin");
|
||||||
|
|
||||||
|
if (isProtectedPage) {
|
||||||
|
// 添加点击劫持防护头
|
||||||
|
headers.add("X-Frame-Options", "DENY");
|
||||||
|
// 改成完整的 CSP,仍保留“禁止被嵌套”
|
||||||
|
headers.add("Content-Security-Policy",
|
||||||
|
"default-src 'self'; " + // 默认仅本域
|
||||||
|
"script-src 'self' https://code.jquery.com; " + // 允许 jQuery CDN
|
||||||
|
"style-src 'self' 'unsafe-inline'; " + // 本域 CSS + 内联
|
||||||
|
"img-src 'self' data:; " + // 本域图片、data URI
|
||||||
|
"frame-ancestors 'none'"); // 继续禁止被 iframe
|
||||||
|
// 添加其他推荐的安全头
|
||||||
|
// headers.add("X-Content-Type-Options", "nosniff");
|
||||||
|
// headers.add("X-XSS-Protection", "1; mode=block");
|
||||||
|
// headers.add("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
|
||||||
|
|
||||||
|
log.info("为受保护路径 {} 添加严格安全头部", path);
|
||||||
|
|
||||||
|
// 调试日志
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("设置的严格安全头部:");
|
||||||
|
log.debug(" X-Frame-Options: DENY");
|
||||||
|
log.debug(" Content-Security-Policy: frame-ancestors 'none'");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 即使不是受保护路径,也添加基本安全头
|
||||||
|
headers.add("X-Frame-Options", "SAMEORIGIN");
|
||||||
|
// 改成完整的 CSP,仍保留“禁止被嵌套”
|
||||||
|
headers.add("Content-Security-Policy",
|
||||||
|
"default-src 'self'; " + // 默认仅本域
|
||||||
|
"script-src 'self' https://code.jquery.com; " + // 允许 jQuery CDN
|
||||||
|
"style-src 'self' 'unsafe-inline'; " + // 本域 CSS + 内联
|
||||||
|
"img-src 'self' data:; " + // 本域图片、data URI
|
||||||
|
"frame-ancestors 'none'"); // 继续禁止被 iframe
|
||||||
|
//headers.add("X-Content-Type-Options", "nosniff");
|
||||||
|
//headers.add("X-XSS-Protection", "1; mode=block");
|
||||||
|
|
||||||
|
log.debug("为普通路径 {} 添加基本安全头部", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 继续执行过滤器链
|
||||||
|
return chain.filter(exchange);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrder() {
|
||||||
|
// 设置过滤器执行顺序,数字越小优先级越高
|
||||||
|
// 设置为高位值,确保在路由之后执行,能够修改响应头
|
||||||
|
return Ordered.LOWEST_PRECEDENCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查请求路径是否为受保护路径
|
||||||
|
*/
|
||||||
|
private boolean isProtectedPath(String requestPath) {
|
||||||
|
for (String prefix : PROTECTED_PATH_PREFIXES) {
|
||||||
|
if (requestPath.startsWith(prefix)) {
|
||||||
|
log.debug("路径 {} 匹配受保护前缀: {}", requestPath, prefix);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,7 @@ import com.bonus.sgzb.common.security.annotation.EnableCustomConfig;
|
||||||
import com.bonus.sgzb.common.security.annotation.EnableRyFeignClients;
|
import com.bonus.sgzb.common.security.annotation.EnableRyFeignClients;
|
||||||
import com.bonus.sgzb.common.swagger.annotation.EnableCustomSwagger2;
|
import com.bonus.sgzb.common.swagger.annotation.EnableCustomSwagger2;
|
||||||
import org.springframework.boot.web.servlet.MultipartConfigFactory;
|
import org.springframework.boot.web.servlet.MultipartConfigFactory;
|
||||||
|
import org.springframework.boot.web.servlet.ServletComponentScan;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.util.unit.DataSize;
|
import org.springframework.util.unit.DataSize;
|
||||||
|
|
||||||
|
|
@ -22,6 +23,7 @@ import javax.servlet.MultipartConfigElement;
|
||||||
@EnableRyFeignClients
|
@EnableRyFeignClients
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
@EnableEncryptableProperties
|
@EnableEncryptableProperties
|
||||||
|
|
||||||
public class SgzbSystemApplication {
|
public class SgzbSystemApplication {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(SgzbSystemApplication.class, args);
|
SpringApplication.run(SgzbSystemApplication.class, args);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue