From 21415070461911487682fd98c140908836b0a585 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=86=AF=E5=87=AF?= <371894675@qq.com>
Date: Sun, 19 Nov 2023 10:05:36 +0800
Subject: [PATCH] init gateway
---
.gitignore | 46 +++++++
pom.xml | 119 +++++++++++++++++
.../gateway/DragonGatewayApplication.java | 17 +++
.../dragon/gateway/config/CaptchaConfig.java | 82 ++++++++++++
.../dragon/gateway/config/GatewayConfig.java | 21 +++
.../gateway/config/KaptchaTextCreator.java | 61 +++++++++
.../config/RouterFunctionConfiguration.java | 29 +++++
.../gateway/config/SwaggerProvider.java | 76 +++++++++++
.../config/properties/CaptchaProperties.java | 41 ++++++
.../properties/IgnoreWhiteProperties.java | 31 +++++
.../config/properties/XssProperties.java | 44 +++++++
.../gateway/domain/model/CaptchaCodeRes.java | 21 +++
.../gateway/domain/model/ImageCodeRes.java | 23 ++++
.../com/dragon/gateway/filter/AuthFilter.java | 120 ++++++++++++++++++
.../gateway/filter/BlackListUrlFilter.java | 58 +++++++++
.../gateway/filter/CacheRequestFilter.java | 75 +++++++++++
.../gateway/filter/ValidateCodeFilter.java | 69 ++++++++++
.../com/dragon/gateway/filter/XssFilter.java | 114 +++++++++++++++++
.../handler/GatewayExceptionHandler.java | 48 +++++++
.../handler/SentinelFallbackHandler.java | 35 +++++
.../gateway/handler/SwaggerHandler.java | 46 +++++++
.../gateway/handler/ValidateCodeHandler.java | 37 ++++++
.../gateway/service/ValidateCodeService.java | 23 ++++
.../service/impl/ValidateCodeServiceImpl.java | 109 ++++++++++++++++
src/main/resources/banner.txt | 2 +
src/main/resources/bootstrap.yml | 40 ++++++
src/main/resources/logback.xml | 74 +++++++++++
27 files changed, 1461 insertions(+)
create mode 100644 .gitignore
create mode 100644 pom.xml
create mode 100644 src/main/java/com/dragon/gateway/DragonGatewayApplication.java
create mode 100644 src/main/java/com/dragon/gateway/config/CaptchaConfig.java
create mode 100644 src/main/java/com/dragon/gateway/config/GatewayConfig.java
create mode 100644 src/main/java/com/dragon/gateway/config/KaptchaTextCreator.java
create mode 100644 src/main/java/com/dragon/gateway/config/RouterFunctionConfiguration.java
create mode 100644 src/main/java/com/dragon/gateway/config/SwaggerProvider.java
create mode 100644 src/main/java/com/dragon/gateway/config/properties/CaptchaProperties.java
create mode 100644 src/main/java/com/dragon/gateway/config/properties/IgnoreWhiteProperties.java
create mode 100644 src/main/java/com/dragon/gateway/config/properties/XssProperties.java
create mode 100644 src/main/java/com/dragon/gateway/domain/model/CaptchaCodeRes.java
create mode 100644 src/main/java/com/dragon/gateway/domain/model/ImageCodeRes.java
create mode 100644 src/main/java/com/dragon/gateway/filter/AuthFilter.java
create mode 100644 src/main/java/com/dragon/gateway/filter/BlackListUrlFilter.java
create mode 100644 src/main/java/com/dragon/gateway/filter/CacheRequestFilter.java
create mode 100644 src/main/java/com/dragon/gateway/filter/ValidateCodeFilter.java
create mode 100644 src/main/java/com/dragon/gateway/filter/XssFilter.java
create mode 100644 src/main/java/com/dragon/gateway/handler/GatewayExceptionHandler.java
create mode 100644 src/main/java/com/dragon/gateway/handler/SentinelFallbackHandler.java
create mode 100644 src/main/java/com/dragon/gateway/handler/SwaggerHandler.java
create mode 100644 src/main/java/com/dragon/gateway/handler/ValidateCodeHandler.java
create mode 100644 src/main/java/com/dragon/gateway/service/ValidateCodeService.java
create mode 100644 src/main/java/com/dragon/gateway/service/impl/ValidateCodeServiceImpl.java
create mode 100644 src/main/resources/banner.txt
create mode 100644 src/main/resources/bootstrap.yml
create mode 100644 src/main/resources/logback.xml
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..09bdfea
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,46 @@
+######################################################################
+# Build Tools
+
+.gradle
+/build/
+!gradle/wrapper/gradle-wrapper.jar
+
+target/
+!.mvn/wrapper/maven-wrapper.jar
+
+######################################################################
+# IDE
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### JRebel ###
+rebel.xml
+### NetBeans ###
+nbproject/private/
+build/*
+nbbuild/
+dist/
+nbdist/
+.nb-gradle/
+
+######################################################################
+# Others
+*.log
+*.xml.versionsBackup
+*.swp
+
+!*/build/*.java
+!*/build/*.html
+!*/build/*.xml
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..787b442
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,119 @@
+
+
+ com.dragon
+ dragon-parent
+ 3.6.3
+
+ 3.6.3
+ 4.0.0
+
+ dragon-gateway
+
+
+ dragon-gateway网关模块
+
+
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-gateway
+
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-discovery
+
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-config
+
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-sentinel
+
+
+
+
+ com.alibaba.cloud
+ spring-cloud-alibaba-sentinel-gateway
+
+
+
+
+ com.alibaba.csp
+ sentinel-datasource-nacos
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-loadbalancer
+
+
+
+
+ pro.fessional
+ kaptcha
+
+
+
+
+ com.dragon
+ dragon-common-redis
+
+
+
+
+ io.springfox
+ springfox-swagger-ui
+ ${swagger.fox.version}
+
+
+ io.springfox
+ springfox-swagger2
+ ${swagger.fox.version}
+
+
+
+
+
+ ${project.artifactId}
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ repackage
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-deploy-plugin
+
+ true
+
+
+
+
+
+
diff --git a/src/main/java/com/dragon/gateway/DragonGatewayApplication.java b/src/main/java/com/dragon/gateway/DragonGatewayApplication.java
new file mode 100644
index 0000000..79cbafc
--- /dev/null
+++ b/src/main/java/com/dragon/gateway/DragonGatewayApplication.java
@@ -0,0 +1,17 @@
+package com.dragon.gateway;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+
+/**
+ * 网关启动程序
+ *
+ * @author dragon
+ */
+@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
+public class DragonGatewayApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(DragonGatewayApplication.class, args);
+ }
+}
diff --git a/src/main/java/com/dragon/gateway/config/CaptchaConfig.java b/src/main/java/com/dragon/gateway/config/CaptchaConfig.java
new file mode 100644
index 0000000..81ad4c6
--- /dev/null
+++ b/src/main/java/com/dragon/gateway/config/CaptchaConfig.java
@@ -0,0 +1,82 @@
+package com.dragon.gateway.config;
+
+import com.google.code.kaptcha.impl.DefaultKaptcha;
+import com.google.code.kaptcha.util.Config;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.Properties;
+
+import static com.google.code.kaptcha.Constants.*;
+
+/**
+ * 验证码配置
+ *
+ * @author dragon
+ */
+@Configuration
+public class CaptchaConfig {
+ @Bean(name = "captchaProducer")
+ public DefaultKaptcha getKaptchaBean() {
+ DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
+ Properties properties = new Properties();
+ // 是否有边框 默认为true 我们可以自己设置yes,no
+ properties.setProperty(KAPTCHA_BORDER, "yes");
+ // 验证码文本字符颜色 默认为Color.BLACK
+ properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
+ // 验证码图片宽度 默认为200
+ properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
+ // 验证码图片高度 默认为50
+ properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
+ // 验证码文本字符大小 默认为40
+ properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38");
+ // KAPTCHA_SESSION_KEY
+ properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode");
+ // 验证码文本字符长度 默认为5
+ properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
+ // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
+ properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
+ // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
+ properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
+ Config config = new Config(properties);
+ defaultKaptcha.setConfig(config);
+ return defaultKaptcha;
+ }
+
+ @Bean(name = "captchaProducerMath")
+ public DefaultKaptcha getKaptchaBeanMath() {
+ DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
+ Properties properties = new Properties();
+ // 是否有边框 默认为true 我们可以自己设置yes,no
+ properties.setProperty(KAPTCHA_BORDER, "yes");
+ // 边框颜色 默认为Color.BLACK
+ properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90");
+ // 验证码文本字符颜色 默认为Color.BLACK
+ properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue");
+ // 验证码图片宽度 默认为200
+ properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
+ // 验证码图片高度 默认为50
+ properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
+ // 验证码文本字符大小 默认为40
+ properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35");
+ // KAPTCHA_SESSION_KEY
+ properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath");
+ // 验证码文本生成器
+ properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.dragon.gateway.config.KaptchaTextCreator");
+ // 验证码文本字符间距 默认为2
+ properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3");
+ // 验证码文本字符长度 默认为5
+ properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6");
+ // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
+ properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
+ // 验证码噪点颜色 默认为Color.BLACK
+ properties.setProperty(KAPTCHA_NOISE_COLOR, "white");
+ // 干扰实现类
+ properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");
+ // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
+ properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
+ Config config = new Config(properties);
+ defaultKaptcha.setConfig(config);
+ return defaultKaptcha;
+ }
+}
diff --git a/src/main/java/com/dragon/gateway/config/GatewayConfig.java b/src/main/java/com/dragon/gateway/config/GatewayConfig.java
new file mode 100644
index 0000000..5743354
--- /dev/null
+++ b/src/main/java/com/dragon/gateway/config/GatewayConfig.java
@@ -0,0 +1,21 @@
+package com.dragon.gateway.config;
+
+import com.dragon.gateway.handler.SentinelFallbackHandler;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+
+/**
+ * 网关限流配置
+ *
+ * @author dragon
+ */
+@Configuration
+public class GatewayConfig {
+ @Bean
+ @Order(Ordered.HIGHEST_PRECEDENCE)
+ public SentinelFallbackHandler sentinelGatewayExceptionHandler() {
+ return new SentinelFallbackHandler();
+ }
+}
diff --git a/src/main/java/com/dragon/gateway/config/KaptchaTextCreator.java b/src/main/java/com/dragon/gateway/config/KaptchaTextCreator.java
new file mode 100644
index 0000000..767ae7a
--- /dev/null
+++ b/src/main/java/com/dragon/gateway/config/KaptchaTextCreator.java
@@ -0,0 +1,61 @@
+package com.dragon.gateway.config;
+
+import com.google.code.kaptcha.text.impl.DefaultTextCreator;
+
+import java.util.Random;
+
+/**
+ * 验证码文本生成器
+ *
+ * @author dragon
+ */
+public class KaptchaTextCreator extends DefaultTextCreator {
+ private static final String[] CNUMBERS = "0,1,2,3,4,5,6,7,8,9,10".split(",");
+
+ @Override
+ public String getText() {
+ Integer result = 0;
+ Random random = new Random();
+ int x = random.nextInt(10);
+ int y = random.nextInt(10);
+ StringBuilder suChinese = new StringBuilder();
+ int randomoperands = random.nextInt(3);
+ if (randomoperands == 0) {
+ result = x * y;
+ suChinese.append(CNUMBERS[x]);
+ suChinese.append("*");
+ suChinese.append(CNUMBERS[y]);
+ } else if (randomoperands == 1) {
+ if ((x != 0) && y % x == 0) {
+ result = y / x;
+ suChinese.append(CNUMBERS[y]);
+ suChinese.append("/");
+ suChinese.append(CNUMBERS[x]);
+ } else {
+ result = x + y;
+ suChinese.append(CNUMBERS[x]);
+ suChinese.append("+");
+ suChinese.append(CNUMBERS[y]);
+ }
+ } else if (randomoperands == 2) {
+ if (x >= y) {
+ result = x - y;
+ suChinese.append(CNUMBERS[x]);
+ suChinese.append("-");
+ suChinese.append(CNUMBERS[y]);
+ } else {
+ result = y - x;
+ suChinese.append(CNUMBERS[y]);
+ suChinese.append("-");
+ suChinese.append(CNUMBERS[x]);
+ }
+ } else {
+ result = x + y;
+ suChinese.append(CNUMBERS[x]);
+ suChinese.append("+");
+ suChinese.append(CNUMBERS[y]);
+ }
+ suChinese.append("=?@" + result);
+ return suChinese.toString();
+ }
+}
diff --git a/src/main/java/com/dragon/gateway/config/RouterFunctionConfiguration.java b/src/main/java/com/dragon/gateway/config/RouterFunctionConfiguration.java
new file mode 100644
index 0000000..ab03eb6
--- /dev/null
+++ b/src/main/java/com/dragon/gateway/config/RouterFunctionConfiguration.java
@@ -0,0 +1,29 @@
+package com.dragon.gateway.config;
+
+import com.dragon.gateway.handler.ValidateCodeHandler;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.MediaType;
+import org.springframework.web.reactive.function.server.RequestPredicates;
+import org.springframework.web.reactive.function.server.RouterFunction;
+import org.springframework.web.reactive.function.server.RouterFunctions;
+
+/**
+ * 路由配置信息
+ *
+ * @author dragon
+ */
+@Configuration
+public class RouterFunctionConfiguration {
+ @Autowired
+ private ValidateCodeHandler validateCodeHandler;
+
+ @SuppressWarnings("rawtypes")
+ @Bean
+ public RouterFunction routerFunction() {
+ return RouterFunctions.route(
+ RequestPredicates.GET("/code").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),
+ validateCodeHandler);
+ }
+}
diff --git a/src/main/java/com/dragon/gateway/config/SwaggerProvider.java b/src/main/java/com/dragon/gateway/config/SwaggerProvider.java
new file mode 100644
index 0000000..881796d
--- /dev/null
+++ b/src/main/java/com/dragon/gateway/config/SwaggerProvider.java
@@ -0,0 +1,76 @@
+package com.dragon.gateway.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cloud.gateway.config.GatewayProperties;
+import org.springframework.cloud.gateway.route.RouteLocator;
+import org.springframework.cloud.gateway.support.NameUtils;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Component;
+import org.springframework.web.reactive.config.ResourceHandlerRegistry;
+import org.springframework.web.reactive.config.WebFluxConfigurer;
+import springfox.documentation.swagger.web.SwaggerResource;
+import springfox.documentation.swagger.web.SwaggerResourcesProvider;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 聚合系统接口
+ *
+ * @author dragon
+ */
+@Component
+public class SwaggerProvider implements SwaggerResourcesProvider, WebFluxConfigurer {
+ /**
+ * Swagger2默认的url后缀
+ */
+ public static final String SWAGGER2URL = "/v2/api-docs";
+
+ /**
+ * 网关路由
+ */
+ @Lazy
+ @Autowired
+ private RouteLocator routeLocator;
+
+ @Autowired
+ private GatewayProperties gatewayProperties;
+
+ /**
+ * 聚合其他服务接口
+ *
+ * @return
+ */
+ @Override
+ public List get() {
+ List resourceList = new ArrayList<>();
+ List routes = new ArrayList<>();
+ // 获取网关中配置的route
+ routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
+ gatewayProperties.getRoutes().stream()
+ .filter(routeDefinition -> routes
+ .contains(routeDefinition.getId()))
+ .forEach(routeDefinition -> routeDefinition.getPredicates().stream()
+ .filter(predicateDefinition -> "Path".equalsIgnoreCase(predicateDefinition.getName()))
+ .filter(predicateDefinition -> !"dragon-auth".equalsIgnoreCase(routeDefinition.getId()))
+ .forEach(predicateDefinition -> resourceList
+ .add(swaggerResource(routeDefinition.getId(), predicateDefinition.getArgs()
+ .get(NameUtils.GENERATED_NAME_PREFIX + "0").replace("/**", SWAGGER2URL)))));
+ return resourceList;
+ }
+
+ private SwaggerResource swaggerResource(String name, String location) {
+ SwaggerResource swaggerResource = new SwaggerResource();
+ swaggerResource.setName(name);
+ swaggerResource.setLocation(location);
+ swaggerResource.setSwaggerVersion("2.0");
+ return swaggerResource;
+ }
+
+ @Override
+ public void addResourceHandlers(ResourceHandlerRegistry registry) {
+ /** swagger-ui 地址 */
+ registry.addResourceHandler("/swagger-ui/**")
+ .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/");
+ }
+}
diff --git a/src/main/java/com/dragon/gateway/config/properties/CaptchaProperties.java b/src/main/java/com/dragon/gateway/config/properties/CaptchaProperties.java
new file mode 100644
index 0000000..283a556
--- /dev/null
+++ b/src/main/java/com/dragon/gateway/config/properties/CaptchaProperties.java
@@ -0,0 +1,41 @@
+package com.dragon.gateway.config.properties;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 验证码配置
+ *
+ * @author dragon
+ */
+@Configuration
+@RefreshScope
+@ConfigurationProperties(prefix = "security.captcha")
+public class CaptchaProperties {
+ /**
+ * 验证码开关
+ */
+ private Boolean enabled;
+
+ /**
+ * 验证码类型(math 数组计算 char 字符)
+ */
+ private String type;
+
+ public Boolean getEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(Boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+}
diff --git a/src/main/java/com/dragon/gateway/config/properties/IgnoreWhiteProperties.java b/src/main/java/com/dragon/gateway/config/properties/IgnoreWhiteProperties.java
new file mode 100644
index 0000000..79ab422
--- /dev/null
+++ b/src/main/java/com/dragon/gateway/config/properties/IgnoreWhiteProperties.java
@@ -0,0 +1,31 @@
+package com.dragon.gateway.config.properties;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 放行白名单配置
+ *
+ * @author dragon
+ */
+@Configuration
+@RefreshScope
+@ConfigurationProperties(prefix = "security.ignore")
+public class IgnoreWhiteProperties {
+ /**
+ * 放行白名单配置,网关不校验此处的白名单
+ */
+ private List whites = new ArrayList<>();
+
+ public List getWhites() {
+ return whites;
+ }
+
+ public void setWhites(List whites) {
+ this.whites = whites;
+ }
+}
diff --git a/src/main/java/com/dragon/gateway/config/properties/XssProperties.java b/src/main/java/com/dragon/gateway/config/properties/XssProperties.java
new file mode 100644
index 0000000..406f27e
--- /dev/null
+++ b/src/main/java/com/dragon/gateway/config/properties/XssProperties.java
@@ -0,0 +1,44 @@
+package com.dragon.gateway.config.properties;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * XSS跨站脚本配置
+ *
+ * @author dragon
+ */
+@Configuration
+@RefreshScope
+@ConfigurationProperties(prefix = "security.xss")
+public class XssProperties {
+ /**
+ * Xss开关
+ */
+ private Boolean enabled;
+
+ /**
+ * 排除路径
+ */
+ private List excludeUrls = new ArrayList<>();
+
+ public Boolean getEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(Boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public List getExcludeUrls() {
+ return excludeUrls;
+ }
+
+ public void setExcludeUrls(List excludeUrls) {
+ this.excludeUrls = excludeUrls;
+ }
+}
diff --git a/src/main/java/com/dragon/gateway/domain/model/CaptchaCodeRes.java b/src/main/java/com/dragon/gateway/domain/model/CaptchaCodeRes.java
new file mode 100644
index 0000000..ab618fc
--- /dev/null
+++ b/src/main/java/com/dragon/gateway/domain/model/CaptchaCodeRes.java
@@ -0,0 +1,21 @@
+package com.dragon.gateway.domain.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author 冯凯
+ * @version 1.0
+ * @description:圖片驗證碼相應實體類
+ * @date 2023/11/12 20:03
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class CaptchaCodeRes {
+
+ private boolean captchaEnabled;
+}
diff --git a/src/main/java/com/dragon/gateway/domain/model/ImageCodeRes.java b/src/main/java/com/dragon/gateway/domain/model/ImageCodeRes.java
new file mode 100644
index 0000000..237dffa
--- /dev/null
+++ b/src/main/java/com/dragon/gateway/domain/model/ImageCodeRes.java
@@ -0,0 +1,23 @@
+package com.dragon.gateway.domain.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author 冯凯
+ * @version 1.0
+ * @description: 圖片驗證碼相應實體類
+ * @date 2023/11/12 20:07
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class ImageCodeRes {
+
+ private String uuid;
+
+ private String img;
+}
diff --git a/src/main/java/com/dragon/gateway/filter/AuthFilter.java b/src/main/java/com/dragon/gateway/filter/AuthFilter.java
new file mode 100644
index 0000000..6670df1
--- /dev/null
+++ b/src/main/java/com/dragon/gateway/filter/AuthFilter.java
@@ -0,0 +1,120 @@
+package com.dragon.gateway.filter;
+
+import com.dragon.common.core.constant.CacheConstants;
+import com.dragon.common.core.constant.HttpStatus;
+import com.dragon.common.core.constant.SecurityConstants;
+import com.dragon.common.core.constant.TokenConstants;
+import com.dragon.common.core.utils.JwtUtils;
+import com.dragon.common.core.utils.ServletUtils;
+import com.dragon.common.core.utils.StringUtils;
+import com.dragon.common.redis.service.RedisService;
+import com.dragon.gateway.config.properties.IgnoreWhiteProperties;
+import io.jsonwebtoken.Claims;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cloud.gateway.filter.GatewayFilterChain;
+import org.springframework.cloud.gateway.filter.GlobalFilter;
+import org.springframework.core.Ordered;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.stereotype.Component;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+/**
+ * 网关鉴权
+ *
+ * @author dragon
+ */
+@Component
+public class AuthFilter implements GlobalFilter, Ordered {
+ private static final Logger log = LoggerFactory.getLogger(AuthFilter.class);
+
+ // 排除过滤的 uri 地址,nacos自行添加
+ @Autowired
+ private IgnoreWhiteProperties ignoreWhite;
+
+ @Autowired
+ private RedisService redisService;
+
+
+ @Override
+ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
+ ServerHttpRequest request = exchange.getRequest();
+ ServerHttpRequest.Builder mutate = request.mutate();
+
+ String url = request.getURI().getPath();
+ // 跳过不需要验证的路径
+ if (StringUtils.matches(url, ignoreWhite.getWhites())) {
+ return chain.filter(exchange);
+ }
+ String token = getToken(request);
+ if (StringUtils.isEmpty(token)) {
+ return unauthorizedResponse(exchange, "令牌不能为空");
+ }
+ Claims claims = JwtUtils.parseToken(token);
+ if (claims == null) {
+ return unauthorizedResponse(exchange, "令牌已过期或验证不正确!");
+ }
+ String userkey = JwtUtils.getUserKey(claims);
+ boolean islogin = redisService.hasKey(getTokenKey(userkey));
+ if (!islogin) {
+ return unauthorizedResponse(exchange, "登录状态已过期");
+ }
+ String userid = JwtUtils.getUserId(claims);
+ String username = JwtUtils.getUserName(claims);
+ if (StringUtils.isEmpty(userid) || StringUtils.isEmpty(username)) {
+ return unauthorizedResponse(exchange, "令牌验证失败");
+ }
+
+ // 设置用户信息到请求
+ addHeader(mutate, SecurityConstants.USER_KEY, userkey);
+ addHeader(mutate, SecurityConstants.DETAILS_USER_ID, userid);
+ addHeader(mutate, SecurityConstants.DETAILS_USERNAME, username);
+ // 内部请求来源参数清除
+ removeHeader(mutate, SecurityConstants.FROM_SOURCE);
+ return chain.filter(exchange.mutate().request(mutate.build()).build());
+ }
+
+ private void addHeader(ServerHttpRequest.Builder mutate, String name, Object value) {
+ if (value == null) {
+ return;
+ }
+ String valueStr = value.toString();
+ String valueEncode = ServletUtils.urlEncode(valueStr);
+ mutate.header(name, valueEncode);
+ }
+
+ private void removeHeader(ServerHttpRequest.Builder mutate, String name) {
+ mutate.headers(httpHeaders -> httpHeaders.remove(name)).build();
+ }
+
+ private Mono unauthorizedResponse(ServerWebExchange exchange, String msg) {
+ log.error("[鉴权异常处理]请求路径:{}", exchange.getRequest().getPath());
+ return ServletUtils.webFluxResponseWriter(exchange.getResponse(), msg, HttpStatus.UNAUTHORIZED);
+ }
+
+ /**
+ * 获取缓存key
+ */
+ private String getTokenKey(String token) {
+ return CacheConstants.LOGIN_TOKEN_KEY + token;
+ }
+
+ /**
+ * 获取请求token
+ */
+ private String getToken(ServerHttpRequest request) {
+ String token = request.getHeaders().getFirst(TokenConstants.AUTHENTICATION);
+ // 如果前端设置了令牌前缀,则裁剪掉前缀
+ if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstants.PREFIX)) {
+ token = token.replaceFirst(TokenConstants.PREFIX, StringUtils.EMPTY);
+ }
+ return token;
+ }
+
+ @Override
+ public int getOrder() {
+ return -200;
+ }
+}
diff --git a/src/main/java/com/dragon/gateway/filter/BlackListUrlFilter.java b/src/main/java/com/dragon/gateway/filter/BlackListUrlFilter.java
new file mode 100644
index 0000000..726fa6f
--- /dev/null
+++ b/src/main/java/com/dragon/gateway/filter/BlackListUrlFilter.java
@@ -0,0 +1,58 @@
+package com.dragon.gateway.filter;
+
+import com.dragon.common.core.utils.ServletUtils;
+import org.springframework.cloud.gateway.filter.GatewayFilter;
+import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+/**
+ * 黑名单过滤器
+ *
+ * @author dragon
+ */
+@Component
+public class BlackListUrlFilter extends AbstractGatewayFilterFactory {
+ public BlackListUrlFilter() {
+ super(Config.class);
+ }
+
+ @Override
+ public GatewayFilter apply(Config config) {
+ return (exchange, chain) -> {
+
+ String url = exchange.getRequest().getURI().getPath();
+ if (config.matchBlacklist(url)) {
+ return ServletUtils.webFluxResponseWriter(exchange.getResponse(), "请求地址不允许访问");
+ }
+
+ return chain.filter(exchange);
+ };
+ }
+
+ public static class Config {
+ private List blacklistUrl;
+
+ private List blacklistUrlPattern = new ArrayList<>();
+
+ public boolean matchBlacklist(String url) {
+ return !blacklistUrlPattern.isEmpty() && blacklistUrlPattern.stream().anyMatch(p -> p.matcher(url).find());
+ }
+
+ public List getBlacklistUrl() {
+ return blacklistUrl;
+ }
+
+ public void setBlacklistUrl(List blacklistUrl) {
+ this.blacklistUrl = blacklistUrl;
+ this.blacklistUrlPattern.clear();
+ this.blacklistUrl.forEach(url -> {
+ this.blacklistUrlPattern.add(Pattern.compile(url.replaceAll("\\*\\*", "(.*?)"), Pattern.CASE_INSENSITIVE));
+ });
+ }
+ }
+
+}
diff --git a/src/main/java/com/dragon/gateway/filter/CacheRequestFilter.java b/src/main/java/com/dragon/gateway/filter/CacheRequestFilter.java
new file mode 100644
index 0000000..0715c87
--- /dev/null
+++ b/src/main/java/com/dragon/gateway/filter/CacheRequestFilter.java
@@ -0,0 +1,75 @@
+package com.dragon.gateway.filter;
+
+import org.springframework.cloud.gateway.filter.GatewayFilter;
+import org.springframework.cloud.gateway.filter.GatewayFilterChain;
+import org.springframework.cloud.gateway.filter.OrderedGatewayFilter;
+import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
+import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
+import org.springframework.http.HttpMethod;
+import org.springframework.stereotype.Component;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * 获取body请求数据(解决流不能重复读取问题)
+ *
+ * @author dragon
+ */
+@Component
+public class CacheRequestFilter extends AbstractGatewayFilterFactory {
+ public CacheRequestFilter() {
+ super(Config.class);
+ }
+
+ @Override
+ public String name() {
+ return "CacheRequestFilter";
+ }
+
+ @Override
+ public GatewayFilter apply(Config config) {
+ CacheRequestGatewayFilter cacheRequestGatewayFilter = new CacheRequestGatewayFilter();
+ Integer order = config.getOrder();
+ if (order == null) {
+ return cacheRequestGatewayFilter;
+ }
+ return new OrderedGatewayFilter(cacheRequestGatewayFilter, order);
+ }
+
+ @Override
+ public List shortcutFieldOrder() {
+ return Collections.singletonList("order");
+ }
+
+ public static class CacheRequestGatewayFilter implements GatewayFilter {
+ @Override
+ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
+ // GET DELETE 不过滤
+ HttpMethod method = exchange.getRequest().getMethod();
+ if (method == null || method == HttpMethod.GET || method == HttpMethod.DELETE) {
+ return chain.filter(exchange);
+ }
+ return ServerWebExchangeUtils.cacheRequestBodyAndRequest(exchange, (serverHttpRequest) -> {
+ if (serverHttpRequest == exchange.getRequest()) {
+ return chain.filter(exchange);
+ }
+ return chain.filter(exchange.mutate().request(serverHttpRequest).build());
+ });
+ }
+ }
+
+ static class Config {
+ private Integer order;
+
+ public Integer getOrder() {
+ return order;
+ }
+
+ public void setOrder(Integer order) {
+ this.order = order;
+ }
+ }
+}
diff --git a/src/main/java/com/dragon/gateway/filter/ValidateCodeFilter.java b/src/main/java/com/dragon/gateway/filter/ValidateCodeFilter.java
new file mode 100644
index 0000000..e7c90e4
--- /dev/null
+++ b/src/main/java/com/dragon/gateway/filter/ValidateCodeFilter.java
@@ -0,0 +1,69 @@
+package com.dragon.gateway.filter;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.dragon.common.core.utils.ServletUtils;
+import com.dragon.common.core.utils.StringUtils;
+import com.dragon.gateway.config.properties.CaptchaProperties;
+import com.dragon.gateway.service.ValidateCodeService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cloud.gateway.filter.GatewayFilter;
+import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
+import org.springframework.core.io.buffer.DataBuffer;
+import org.springframework.core.io.buffer.DataBufferUtils;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.stereotype.Component;
+import reactor.core.publisher.Flux;
+
+import java.nio.CharBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * 验证码过滤器
+ *
+ * @author dragon
+ */
+@Component
+public class ValidateCodeFilter extends AbstractGatewayFilterFactory