master
parent
b0198d13d9
commit
5f97b88ff5
|
@ -0,0 +1,110 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>com.jing</groupId>
|
||||
<artifactId>jing</artifactId>
|
||||
<version>3.6.4</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>jing-gateway</artifactId>
|
||||
|
||||
<description>
|
||||
jing-gateway网关模块
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- SpringCloud Gateway -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-gateway</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringCloud Alibaba Nacos -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringCloud Alibaba Nacos Config -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringCloud Alibaba Sentinel -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringCloud Alibaba Sentinel Gateway -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Sentinel Datasource Nacos -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-datasource-nacos</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringBoot Actuator -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringCloud Loadbalancer -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-loadbalancer</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--验证码 -->
|
||||
<dependency>
|
||||
<groupId>pro.fessional</groupId>
|
||||
<artifactId>kaptcha</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- RuoYi Common Redis-->
|
||||
<dependency>
|
||||
<groupId>com.jing</groupId>
|
||||
<artifactId>jing-common-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Swagger -->
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-swagger-ui</artifactId>
|
||||
<version>${swagger.fox.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-swagger2</artifactId>
|
||||
<version>${swagger.fox.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,29 @@
|
|||
package com.jing.gateway;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
|
||||
/**
|
||||
* 网关启动程序
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })
|
||||
public class JingGatewayApplication
|
||||
{
|
||||
public static void main(String[] args)
|
||||
{
|
||||
SpringApplication.run(JingGatewayApplication.class, args);
|
||||
System.out.println("(♥◠‿◠)ノ゙ 若依网关启动成功 ლ(´ڡ`ლ)゙ \n" +
|
||||
" .-------. ____ __ \n" +
|
||||
" | _ _ \\ \\ \\ / / \n" +
|
||||
" | ( ' ) | \\ _. / ' \n" +
|
||||
" |(_ o _) / _( )_ .' \n" +
|
||||
" | (_,_).' __ ___(_ o _)' \n" +
|
||||
" | |\\ \\ | || |(_,_)' \n" +
|
||||
" | | \\ `' /| `-' / \n" +
|
||||
" | | \\ / \\ / \n" +
|
||||
" ''-' `'-' `-..-' ");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package com.jing.gateway.config;
|
||||
|
||||
import java.util.Properties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import com.google.code.kaptcha.impl.DefaultKaptcha;
|
||||
import com.google.code.kaptcha.util.Config;
|
||||
import static com.google.code.kaptcha.Constants.*;
|
||||
|
||||
/**
|
||||
* 验证码配置
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@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.jing.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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.jing.gateway.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import com.jing.gateway.handler.SentinelFallbackHandler;
|
||||
|
||||
/**
|
||||
* 网关限流配置
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Configuration
|
||||
public class GatewayConfig
|
||||
{
|
||||
@Bean
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
public SentinelFallbackHandler sentinelGatewayExceptionHandler()
|
||||
{
|
||||
return new SentinelFallbackHandler();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package com.jing.gateway.config;
|
||||
|
||||
import java.util.Random;
|
||||
import com.google.code.kaptcha.text.impl.DefaultTextCreator;
|
||||
|
||||
/**
|
||||
* 验证码文本生成器
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package com.jing.gateway.config;
|
||||
|
||||
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;
|
||||
import com.jing.gateway.handler.ValidateCodeHandler;
|
||||
|
||||
/**
|
||||
* 路由配置信息
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package com.jing.gateway.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 聚合系统接口
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@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<SwaggerResource> get()
|
||||
{
|
||||
List<SwaggerResource> resourceList = new ArrayList<>();
|
||||
List<String> 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 -> !"jing-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/");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package com.jing.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 ruoyi
|
||||
*/
|
||||
@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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.jing.gateway.config.properties;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 放行白名单配置
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Configuration
|
||||
@RefreshScope
|
||||
@ConfigurationProperties(prefix = "security.ignore")
|
||||
public class IgnoreWhiteProperties
|
||||
{
|
||||
/**
|
||||
* 放行白名单配置,网关不校验此处的白名单
|
||||
*/
|
||||
private List<String> whites = new ArrayList<>();
|
||||
|
||||
public List<String> getWhites()
|
||||
{
|
||||
return whites;
|
||||
}
|
||||
|
||||
public void setWhites(List<String> whites)
|
||||
{
|
||||
this.whites = whites;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package com.jing.gateway.config.properties;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* XSS跨站脚本配置
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Configuration
|
||||
@RefreshScope
|
||||
@ConfigurationProperties(prefix = "security.xss")
|
||||
public class XssProperties
|
||||
{
|
||||
/**
|
||||
* Xss开关
|
||||
*/
|
||||
private Boolean enabled;
|
||||
|
||||
/**
|
||||
* 排除路径
|
||||
*/
|
||||
private List<String> excludeUrls = new ArrayList<>();
|
||||
|
||||
public Boolean getEnabled()
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(Boolean enabled)
|
||||
{
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public List<String> getExcludeUrls()
|
||||
{
|
||||
return excludeUrls;
|
||||
}
|
||||
|
||||
public void setExcludeUrls(List<String> excludeUrls)
|
||||
{
|
||||
this.excludeUrls = excludeUrls;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
package com.jing.gateway.filter;
|
||||
|
||||
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 com.jing.common.core.constant.CacheConstants;
|
||||
import com.jing.common.core.constant.HttpStatus;
|
||||
import com.jing.common.core.constant.SecurityConstants;
|
||||
import com.jing.common.core.constant.TokenConstants;
|
||||
import com.jing.common.core.utils.JwtUtils;
|
||||
import com.jing.common.core.utils.ServletUtils;
|
||||
import com.jing.common.core.utils.StringUtils;
|
||||
import com.jing.common.redis.service.RedisService;
|
||||
import com.jing.gateway.config.properties.IgnoreWhiteProperties;
|
||||
import io.jsonwebtoken.Claims;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 网关鉴权
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@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<Void> 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<Void> 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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package com.jing.gateway.filter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilter;
|
||||
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.jing.common.core.utils.ServletUtils;
|
||||
|
||||
/**
|
||||
* 黑名单过滤器
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Component
|
||||
public class BlackListUrlFilter extends AbstractGatewayFilterFactory<BlackListUrlFilter.Config>
|
||||
{
|
||||
@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 BlackListUrlFilter()
|
||||
{
|
||||
super(Config.class);
|
||||
}
|
||||
|
||||
public static class Config
|
||||
{
|
||||
private List<String> blacklistUrl;
|
||||
|
||||
private List<Pattern> blacklistUrlPattern = new ArrayList<>();
|
||||
|
||||
public boolean matchBlacklist(String url)
|
||||
{
|
||||
return !blacklistUrlPattern.isEmpty() && blacklistUrlPattern.stream().anyMatch(p -> p.matcher(url).find());
|
||||
}
|
||||
|
||||
public List<String> getBlacklistUrl()
|
||||
{
|
||||
return blacklistUrl;
|
||||
}
|
||||
|
||||
public void setBlacklistUrl(List<String> blacklistUrl)
|
||||
{
|
||||
this.blacklistUrl = blacklistUrl;
|
||||
this.blacklistUrlPattern.clear();
|
||||
this.blacklistUrl.forEach(url -> {
|
||||
this.blacklistUrlPattern.add(Pattern.compile(url.replaceAll("\\*\\*", "(.*?)"), Pattern.CASE_INSENSITIVE));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
package com.jing.gateway.filter;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 获取body请求数据(解决流不能重复读取问题)
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Component
|
||||
public class CacheRequestFilter extends AbstractGatewayFilterFactory<CacheRequestFilter.Config>
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
public static class CacheRequestGatewayFilter implements GatewayFilter
|
||||
{
|
||||
@Override
|
||||
public Mono<Void> 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());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> shortcutFieldOrder()
|
||||
{
|
||||
return Collections.singletonList("order");
|
||||
}
|
||||
|
||||
static class Config
|
||||
{
|
||||
private Integer order;
|
||||
|
||||
public Integer getOrder()
|
||||
{
|
||||
return order;
|
||||
}
|
||||
|
||||
public void setOrder(Integer order)
|
||||
{
|
||||
this.order = order;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package com.jing.gateway.filter;
|
||||
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
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 com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.jing.common.core.utils.ServletUtils;
|
||||
import com.jing.common.core.utils.StringUtils;
|
||||
import com.jing.gateway.config.properties.CaptchaProperties;
|
||||
import com.jing.gateway.service.ValidateCodeService;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
/**
|
||||
* 验证码过滤器
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Component
|
||||
public class ValidateCodeFilter extends AbstractGatewayFilterFactory<Object>
|
||||
{
|
||||
private final static String[] VALIDATE_URL = new String[] { "/auth/login", "/auth/register" };
|
||||
|
||||
@Autowired
|
||||
private ValidateCodeService validateCodeService;
|
||||
|
||||
@Autowired
|
||||
private CaptchaProperties captchaProperties;
|
||||
|
||||
private static final String CODE = "code";
|
||||
|
||||
private static final String UUID = "uuid";
|
||||
|
||||
@Override
|
||||
public GatewayFilter apply(Object config)
|
||||
{
|
||||
return (exchange, chain) -> {
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
|
||||
// 非登录/注册请求或验证码关闭,不处理
|
||||
if (!StringUtils.equalsAnyIgnoreCase(request.getURI().getPath(), VALIDATE_URL) || !captchaProperties.getEnabled())
|
||||
{
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
String rspStr = resolveBodyFromRequest(request);
|
||||
JSONObject obj = JSON.parseObject(rspStr);
|
||||
validateCodeService.checkCaptcha(obj.getString(CODE), obj.getString(UUID));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return ServletUtils.webFluxResponseWriter(exchange.getResponse(), e.getMessage());
|
||||
}
|
||||
return chain.filter(exchange);
|
||||
};
|
||||
}
|
||||
|
||||
private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest)
|
||||
{
|
||||
// 获取请求体
|
||||
Flux<DataBuffer> body = serverHttpRequest.getBody();
|
||||
AtomicReference<String> bodyRef = new AtomicReference<>();
|
||||
body.subscribe(buffer -> {
|
||||
CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
|
||||
DataBufferUtils.release(buffer);
|
||||
bodyRef.set(charBuffer.toString());
|
||||
});
|
||||
return bodyRef.get();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
package com.jing.gateway.filter;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
|
||||
import org.springframework.core.io.buffer.NettyDataBufferFactory;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import com.jing.common.core.utils.StringUtils;
|
||||
import com.jing.common.core.utils.html.EscapeUtil;
|
||||
import com.jing.gateway.config.properties.XssProperties;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 跨站脚本过滤器
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Component
|
||||
@ConditionalOnProperty(value = "security.xss.enabled", havingValue = "true")
|
||||
public class XssFilter implements GlobalFilter, Ordered
|
||||
{
|
||||
// 跨站脚本的 xss 配置,nacos自行添加
|
||||
@Autowired
|
||||
private XssProperties xss;
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
|
||||
{
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
// xss开关未开启 或 通过nacos关闭,不过滤
|
||||
if (!xss.getEnabled())
|
||||
{
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
// GET DELETE 不过滤
|
||||
HttpMethod method = request.getMethod();
|
||||
if (method == null || method == HttpMethod.GET || method == HttpMethod.DELETE)
|
||||
{
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
// 非json类型,不过滤
|
||||
if (!isJsonRequest(exchange))
|
||||
{
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
// excludeUrls 不过滤
|
||||
String url = request.getURI().getPath();
|
||||
if (StringUtils.matches(url, xss.getExcludeUrls()))
|
||||
{
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
ServerHttpRequestDecorator httpRequestDecorator = requestDecorator(exchange);
|
||||
return chain.filter(exchange.mutate().request(httpRequestDecorator).build());
|
||||
|
||||
}
|
||||
|
||||
private ServerHttpRequestDecorator requestDecorator(ServerWebExchange exchange)
|
||||
{
|
||||
ServerHttpRequestDecorator serverHttpRequestDecorator = new ServerHttpRequestDecorator(exchange.getRequest())
|
||||
{
|
||||
@Override
|
||||
public Flux<DataBuffer> getBody()
|
||||
{
|
||||
Flux<DataBuffer> body = super.getBody();
|
||||
return body.buffer().map(dataBuffers -> {
|
||||
DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
|
||||
DataBuffer join = dataBufferFactory.join(dataBuffers);
|
||||
byte[] content = new byte[join.readableByteCount()];
|
||||
join.read(content);
|
||||
DataBufferUtils.release(join);
|
||||
String bodyStr = new String(content, StandardCharsets.UTF_8);
|
||||
// 防xss攻击过滤
|
||||
bodyStr = EscapeUtil.clean(bodyStr);
|
||||
// 转成字节
|
||||
byte[] bytes = bodyStr.getBytes(StandardCharsets.UTF_8);
|
||||
NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
|
||||
DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
|
||||
buffer.write(bytes);
|
||||
return buffer;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders getHeaders()
|
||||
{
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
httpHeaders.putAll(super.getHeaders());
|
||||
// 由于修改了请求体的body,导致content-length长度不确定,因此需要删除原先的content-length
|
||||
httpHeaders.remove(HttpHeaders.CONTENT_LENGTH);
|
||||
httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
|
||||
return httpHeaders;
|
||||
}
|
||||
|
||||
};
|
||||
return serverHttpRequestDecorator;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是Json请求
|
||||
*
|
||||
* @param exchange HTTP请求
|
||||
*/
|
||||
public boolean isJsonRequest(ServerWebExchange exchange)
|
||||
{
|
||||
String header = exchange.getRequest().getHeaders().getFirst(HttpHeaders.CONTENT_TYPE);
|
||||
return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder()
|
||||
{
|
||||
return -100;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package com.jing.gateway.handler;
|
||||
|
||||
import org.springframework.cloud.gateway.support.NotFoundException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import com.jing.common.core.utils.ServletUtils;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 网关统一异常处理
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Order(-1)
|
||||
@Configuration
|
||||
public class GatewayExceptionHandler implements ErrorWebExceptionHandler
|
||||
{
|
||||
private static final Logger log = LoggerFactory.getLogger(GatewayExceptionHandler.class);
|
||||
|
||||
@Override
|
||||
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex)
|
||||
{
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
|
||||
if (exchange.getResponse().isCommitted())
|
||||
{
|
||||
return Mono.error(ex);
|
||||
}
|
||||
|
||||
String msg;
|
||||
|
||||
if (ex instanceof NotFoundException)
|
||||
{
|
||||
msg = "服务未找到";
|
||||
}
|
||||
else if (ex instanceof ResponseStatusException)
|
||||
{
|
||||
ResponseStatusException responseStatusException = (ResponseStatusException) ex;
|
||||
msg = responseStatusException.getMessage();
|
||||
}
|
||||
else
|
||||
{
|
||||
msg = "内部服务器错误";
|
||||
}
|
||||
|
||||
log.error("[网关异常处理]请求路径:{},异常信息:{}", exchange.getRequest().getPath(), ex.getMessage());
|
||||
|
||||
return ServletUtils.webFluxResponseWriter(response, msg);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package com.jing.gateway.handler;
|
||||
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
import com.jing.common.core.utils.ServletUtils;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.WebExceptionHandler;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 自定义限流异常处理
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class SentinelFallbackHandler implements WebExceptionHandler
|
||||
{
|
||||
private Mono<Void> writeResponse(ServerResponse response, ServerWebExchange exchange)
|
||||
{
|
||||
return ServletUtils.webFluxResponseWriter(exchange.getResponse(), "请求超过最大数,请稍候再试");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex)
|
||||
{
|
||||
if (exchange.getResponse().isCommitted())
|
||||
{
|
||||
return Mono.error(ex);
|
||||
}
|
||||
if (!BlockException.isBlockException(ex))
|
||||
{
|
||||
return Mono.error(ex);
|
||||
}
|
||||
return handleBlockedRequest(exchange, ex).flatMap(response -> writeResponse(response, exchange));
|
||||
}
|
||||
|
||||
private Mono<ServerResponse> handleBlockedRequest(ServerWebExchange exchange, Throwable throwable)
|
||||
{
|
||||
return GatewayCallbackManager.getBlockHandler().handleRequest(exchange, throwable);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package com.jing.gateway.handler;
|
||||
|
||||
import java.util.Optional;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import reactor.core.publisher.Mono;
|
||||
import springfox.documentation.swagger.web.SecurityConfiguration;
|
||||
import springfox.documentation.swagger.web.SecurityConfigurationBuilder;
|
||||
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
|
||||
import springfox.documentation.swagger.web.UiConfiguration;
|
||||
import springfox.documentation.swagger.web.UiConfigurationBuilder;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/swagger-resources")
|
||||
public class SwaggerHandler
|
||||
{
|
||||
@Autowired(required = false)
|
||||
private SecurityConfiguration securityConfiguration;
|
||||
|
||||
@Autowired(required = false)
|
||||
private UiConfiguration uiConfiguration;
|
||||
|
||||
private final SwaggerResourcesProvider swaggerResources;
|
||||
|
||||
@Autowired
|
||||
public SwaggerHandler(SwaggerResourcesProvider swaggerResources)
|
||||
{
|
||||
this.swaggerResources = swaggerResources;
|
||||
}
|
||||
|
||||
@GetMapping("/configuration/security")
|
||||
public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration()
|
||||
{
|
||||
return Mono.just(new ResponseEntity<>(
|
||||
Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()),
|
||||
HttpStatus.OK));
|
||||
}
|
||||
|
||||
@GetMapping("/configuration/ui")
|
||||
public Mono<ResponseEntity<UiConfiguration>> uiConfiguration()
|
||||
{
|
||||
return Mono.just(new ResponseEntity<>(
|
||||
Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK));
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@GetMapping("")
|
||||
public Mono<ResponseEntity> swaggerResources()
|
||||
{
|
||||
return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package com.jing.gateway.handler;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.reactive.function.BodyInserters;
|
||||
import org.springframework.web.reactive.function.server.HandlerFunction;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
import com.jing.common.core.exception.CaptchaException;
|
||||
import com.jing.common.core.web.domain.AjaxResult;
|
||||
import com.jing.gateway.service.ValidateCodeService;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 验证码获取
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Component
|
||||
public class ValidateCodeHandler implements HandlerFunction<ServerResponse>
|
||||
{
|
||||
@Autowired
|
||||
private ValidateCodeService validateCodeService;
|
||||
|
||||
@Override
|
||||
public Mono<ServerResponse> handle(ServerRequest serverRequest)
|
||||
{
|
||||
AjaxResult ajax;
|
||||
try
|
||||
{
|
||||
ajax = validateCodeService.createCaptcha();
|
||||
}
|
||||
catch (CaptchaException | IOException e)
|
||||
{
|
||||
return Mono.error(e);
|
||||
}
|
||||
return ServerResponse.status(HttpStatus.OK).body(BodyInserters.fromValue(ajax));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.jing.gateway.service;
|
||||
|
||||
import java.io.IOException;
|
||||
import com.jing.common.core.exception.CaptchaException;
|
||||
import com.jing.common.core.web.domain.AjaxResult;
|
||||
|
||||
/**
|
||||
* 验证码处理
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public interface ValidateCodeService
|
||||
{
|
||||
/**
|
||||
* 生成验证码
|
||||
*/
|
||||
public AjaxResult createCaptcha() throws IOException, CaptchaException;
|
||||
|
||||
/**
|
||||
* 校验验证码
|
||||
*/
|
||||
public void checkCaptcha(String key, String value) throws CaptchaException;
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
package com.jing.gateway.service.impl;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.annotation.Resource;
|
||||
import javax.imageio.ImageIO;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.FastByteArrayOutputStream;
|
||||
import com.google.code.kaptcha.Producer;
|
||||
import com.jing.common.core.constant.CacheConstants;
|
||||
import com.jing.common.core.constant.Constants;
|
||||
import com.jing.common.core.exception.CaptchaException;
|
||||
import com.jing.common.core.utils.StringUtils;
|
||||
import com.jing.common.core.utils.sign.Base64;
|
||||
import com.jing.common.core.utils.uuid.IdUtils;
|
||||
import com.jing.common.core.web.domain.AjaxResult;
|
||||
import com.jing.common.redis.service.RedisService;
|
||||
import com.jing.gateway.config.properties.CaptchaProperties;
|
||||
import com.jing.gateway.service.ValidateCodeService;
|
||||
|
||||
/**
|
||||
* 验证码实现处理
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Service
|
||||
public class ValidateCodeServiceImpl implements ValidateCodeService
|
||||
{
|
||||
@Resource(name = "captchaProducer")
|
||||
private Producer captchaProducer;
|
||||
|
||||
@Resource(name = "captchaProducerMath")
|
||||
private Producer captchaProducerMath;
|
||||
|
||||
@Autowired
|
||||
private RedisService redisService;
|
||||
|
||||
@Autowired
|
||||
private CaptchaProperties captchaProperties;
|
||||
|
||||
/**
|
||||
* 生成验证码
|
||||
*/
|
||||
@Override
|
||||
public AjaxResult createCaptcha() throws IOException, CaptchaException
|
||||
{
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
boolean captchaEnabled = captchaProperties.getEnabled();
|
||||
ajax.put("captchaEnabled", captchaEnabled);
|
||||
if (!captchaEnabled)
|
||||
{
|
||||
return ajax;
|
||||
}
|
||||
|
||||
// 保存验证码信息
|
||||
String uuid = IdUtils.simpleUUID();
|
||||
String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
|
||||
|
||||
String capStr = null, code = null;
|
||||
BufferedImage image = null;
|
||||
|
||||
String captchaType = captchaProperties.getType();
|
||||
// 生成验证码
|
||||
if ("math".equals(captchaType))
|
||||
{
|
||||
String capText = captchaProducerMath.createText();
|
||||
capStr = capText.substring(0, capText.lastIndexOf("@"));
|
||||
code = capText.substring(capText.lastIndexOf("@") + 1);
|
||||
image = captchaProducerMath.createImage(capStr);
|
||||
}
|
||||
else if ("char".equals(captchaType))
|
||||
{
|
||||
capStr = code = captchaProducer.createText();
|
||||
image = captchaProducer.createImage(capStr);
|
||||
}
|
||||
|
||||
redisService.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
|
||||
// 转换流信息写出
|
||||
FastByteArrayOutputStream os = new FastByteArrayOutputStream();
|
||||
try
|
||||
{
|
||||
ImageIO.write(image, "jpg", os);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
return AjaxResult.error(e.getMessage());
|
||||
}
|
||||
|
||||
ajax.put("uuid", uuid);
|
||||
ajax.put("img", Base64.encode(os.toByteArray()));
|
||||
return ajax;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验验证码
|
||||
*/
|
||||
@Override
|
||||
public void checkCaptcha(String code, String uuid) throws CaptchaException
|
||||
{
|
||||
if (StringUtils.isEmpty(code))
|
||||
{
|
||||
throw new CaptchaException("验证码不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(uuid))
|
||||
{
|
||||
throw new CaptchaException("验证码已失效");
|
||||
}
|
||||
String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
|
||||
String captcha = redisService.getCacheObject(verifyKey);
|
||||
redisService.deleteObject(verifyKey);
|
||||
|
||||
if (!code.equalsIgnoreCase(captcha))
|
||||
{
|
||||
throw new CaptchaException("验证码错误");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
Spring Boot Version: ${spring-boot.version}
|
||||
Spring Application Name: ${spring.application.name}
|
||||
_ _
|
||||
(_) | |
|
||||
_ __ _ _ ___ _ _ _ ______ __ _ __ _ | |_ ___ __ __ __ _ _ _
|
||||
| '__|| | | | / _ \ | | | || ||______| / _` | / _` || __| / _ \\ \ /\ / / / _` || | | |
|
||||
| | | |_| || (_) || |_| || | | (_| || (_| || |_ | __/ \ V V / | (_| || |_| |
|
||||
|_| \__,_| \___/ \__, ||_| \__, | \__,_| \__| \___| \_/\_/ \__,_| \__, |
|
||||
__/ | __/ | __/ |
|
||||
|___/ |___/ |___/
|
|
@ -0,0 +1,42 @@
|
|||
# Tomcat
|
||||
server:
|
||||
port: 8080
|
||||
|
||||
# Spring
|
||||
spring:
|
||||
application:
|
||||
# 应用名称
|
||||
name: jing-gateway
|
||||
profiles:
|
||||
# 环境配置
|
||||
active: dev
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
# 服务注册地址
|
||||
server-addr: 111.231.174.71:8848
|
||||
namespace: a2f5cf16-e7f3-40f0-9cd7-171a055cacd2
|
||||
config:
|
||||
# 配置中心地址
|
||||
server-addr: 111.231.174.71:8848
|
||||
namespace: a2f5cf16-e7f3-40f0-9cd7-171a055cacd2
|
||||
# 配置文件格式
|
||||
file-extension: yml
|
||||
# 共享配置
|
||||
shared-configs:
|
||||
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
||||
sentinel:
|
||||
# 取消控制台懒加载
|
||||
eager: true
|
||||
transport:
|
||||
# 控制台地址
|
||||
dashboard: 111.231.174.71:8718
|
||||
# nacos配置持久化
|
||||
datasource:
|
||||
ds1:
|
||||
nacos:
|
||||
server-addr: 111.231.174.71:8848
|
||||
dataId: sentinel-jing-gateway
|
||||
groupId: DEFAULT_GROUP
|
||||
data-type: json
|
||||
rule-type: gw-flow
|
|
@ -0,0 +1,74 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration scan="true" scanPeriod="60 seconds" debug="false">
|
||||
<!-- 日志存放路径 -->
|
||||
<property name="log.path" value="logs/jing-gateway" />
|
||||
<!-- 日志输出格式 -->
|
||||
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
|
||||
|
||||
<!-- 控制台输出 -->
|
||||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- 系统日志输出 -->
|
||||
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/info.log</file>
|
||||
<!-- 循环政策:基于时间创建日志文件 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 日志文件名格式 -->
|
||||
<fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<!-- 日志最大的历史 60天 -->
|
||||
<maxHistory>60</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!-- 过滤的级别 -->
|
||||
<level>INFO</level>
|
||||
<!-- 匹配时的操作:接收(记录) -->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!-- 不匹配时的操作:拒绝(不记录) -->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/error.log</file>
|
||||
<!-- 循环政策:基于时间创建日志文件 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 日志文件名格式 -->
|
||||
<fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<!-- 日志最大的历史 60天 -->
|
||||
<maxHistory>60</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!-- 过滤的级别 -->
|
||||
<level>ERROR</level>
|
||||
<!-- 匹配时的操作:接收(记录) -->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!-- 不匹配时的操作:拒绝(不记录) -->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<!-- 系统模块日志级别控制 -->
|
||||
<logger name="com.jing" level="info" />
|
||||
<!-- Spring日志级别控制 -->
|
||||
<logger name="org.springframework" level="warn" />
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="console" />
|
||||
</root>
|
||||
|
||||
<!--系统操作日志-->
|
||||
<root level="info">
|
||||
<appender-ref ref="file_info" />
|
||||
<appender-ref ref="file_error" />
|
||||
</root>
|
||||
</configuration>
|
|
@ -0,0 +1,10 @@
|
|||
Spring Boot Version: ${spring-boot.version}
|
||||
Spring Application Name: ${spring.application.name}
|
||||
_ _
|
||||
(_) | |
|
||||
_ __ _ _ ___ _ _ _ ______ __ _ __ _ | |_ ___ __ __ __ _ _ _
|
||||
| '__|| | | | / _ \ | | | || ||______| / _` | / _` || __| / _ \\ \ /\ / / / _` || | | |
|
||||
| | | |_| || (_) || |_| || | | (_| || (_| || |_ | __/ \ V V / | (_| || |_| |
|
||||
|_| \__,_| \___/ \__, ||_| \__, | \__,_| \__| \___| \_/\_/ \__,_| \__, |
|
||||
__/ | __/ | __/ |
|
||||
|___/ |___/ |___/
|
|
@ -0,0 +1,42 @@
|
|||
# Tomcat
|
||||
server:
|
||||
port: 8080
|
||||
|
||||
# Spring
|
||||
spring:
|
||||
application:
|
||||
# 应用名称
|
||||
name: jing-gateway
|
||||
profiles:
|
||||
# 环境配置
|
||||
active: dev
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
# 服务注册地址
|
||||
server-addr: 111.231.174.71:8848
|
||||
namespace: a2f5cf16-e7f3-40f0-9cd7-171a055cacd2
|
||||
config:
|
||||
# 配置中心地址
|
||||
server-addr: 111.231.174.71:8848
|
||||
namespace: a2f5cf16-e7f3-40f0-9cd7-171a055cacd2
|
||||
# 配置文件格式
|
||||
file-extension: yml
|
||||
# 共享配置
|
||||
shared-configs:
|
||||
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
||||
sentinel:
|
||||
# 取消控制台懒加载
|
||||
eager: true
|
||||
transport:
|
||||
# 控制台地址
|
||||
dashboard: 111.231.174.71:8718
|
||||
# nacos配置持久化
|
||||
datasource:
|
||||
ds1:
|
||||
nacos:
|
||||
server-addr: 111.231.174.71:8848
|
||||
dataId: sentinel-jing-gateway
|
||||
groupId: DEFAULT_GROUP
|
||||
data-type: json
|
||||
rule-type: gw-flow
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,74 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration scan="true" scanPeriod="60 seconds" debug="false">
|
||||
<!-- 日志存放路径 -->
|
||||
<property name="log.path" value="logs/jing-gateway" />
|
||||
<!-- 日志输出格式 -->
|
||||
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
|
||||
|
||||
<!-- 控制台输出 -->
|
||||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- 系统日志输出 -->
|
||||
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/info.log</file>
|
||||
<!-- 循环政策:基于时间创建日志文件 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 日志文件名格式 -->
|
||||
<fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<!-- 日志最大的历史 60天 -->
|
||||
<maxHistory>60</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!-- 过滤的级别 -->
|
||||
<level>INFO</level>
|
||||
<!-- 匹配时的操作:接收(记录) -->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!-- 不匹配时的操作:拒绝(不记录) -->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/error.log</file>
|
||||
<!-- 循环政策:基于时间创建日志文件 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 日志文件名格式 -->
|
||||
<fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<!-- 日志最大的历史 60天 -->
|
||||
<maxHistory>60</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!-- 过滤的级别 -->
|
||||
<level>ERROR</level>
|
||||
<!-- 匹配时的操作:接收(记录) -->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!-- 不匹配时的操作:拒绝(不记录) -->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<!-- 系统模块日志级别控制 -->
|
||||
<logger name="com.jing" level="info" />
|
||||
<!-- Spring日志级别控制 -->
|
||||
<logger name="org.springframework" level="warn" />
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="console" />
|
||||
</root>
|
||||
|
||||
<!--系统操作日志-->
|
||||
<root level="info">
|
||||
<appender-ref ref="file_info" />
|
||||
<appender-ref ref="file_error" />
|
||||
</root>
|
||||
</configuration>
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,3 @@
|
|||
artifactId=jing-gateway
|
||||
groupId=com.jing
|
||||
version=3.6.4
|
|
@ -0,0 +1,24 @@
|
|||
com\jing\gateway\JingGatewayApplication.class
|
||||
com\jing\gateway\config\CaptchaConfig.class
|
||||
com\jing\gateway\config\properties\IgnoreWhiteProperties.class
|
||||
com\jing\gateway\handler\SwaggerHandler.class
|
||||
com\jing\gateway\service\impl\ValidateCodeServiceImpl.class
|
||||
com\jing\gateway\handler\ValidateCodeHandler.class
|
||||
com\jing\gateway\config\properties\CaptchaProperties.class
|
||||
com\jing\gateway\config\properties\XssProperties.class
|
||||
com\jing\gateway\filter\BlackListUrlFilter.class
|
||||
com\jing\gateway\filter\AuthFilter.class
|
||||
com\jing\gateway\config\RouterFunctionConfiguration.class
|
||||
com\jing\gateway\config\SwaggerProvider.class
|
||||
com\jing\gateway\handler\SentinelFallbackHandler.class
|
||||
com\jing\gateway\config\KaptchaTextCreator.class
|
||||
com\jing\gateway\filter\BlackListUrlFilter$Config.class
|
||||
com\jing\gateway\filter\CacheRequestFilter$Config.class
|
||||
com\jing\gateway\filter\XssFilter$1.class
|
||||
com\jing\gateway\filter\XssFilter.class
|
||||
com\jing\gateway\service\ValidateCodeService.class
|
||||
com\jing\gateway\filter\ValidateCodeFilter.class
|
||||
com\jing\gateway\handler\GatewayExceptionHandler.class
|
||||
com\jing\gateway\filter\CacheRequestFilter$CacheRequestGatewayFilter.class
|
||||
com\jing\gateway\filter\CacheRequestFilter.class
|
||||
com\jing\gateway\config\GatewayConfig.class
|
|
@ -0,0 +1,20 @@
|
|||
F:\Welcome-2105A\20240521142828\jing-cloud\jing-gateway\src\main\java\com\jing\gateway\config\properties\CaptchaProperties.java
|
||||
F:\Welcome-2105A\20240521142828\jing-cloud\jing-gateway\src\main\java\com\jing\gateway\handler\ValidateCodeHandler.java
|
||||
F:\Welcome-2105A\20240521142828\jing-cloud\jing-gateway\src\main\java\com\jing\gateway\handler\GatewayExceptionHandler.java
|
||||
F:\Welcome-2105A\20240521142828\jing-cloud\jing-gateway\src\main\java\com\jing\gateway\JingGatewayApplication.java
|
||||
F:\Welcome-2105A\20240521142828\jing-cloud\jing-gateway\src\main\java\com\jing\gateway\config\KaptchaTextCreator.java
|
||||
F:\Welcome-2105A\20240521142828\jing-cloud\jing-gateway\src\main\java\com\jing\gateway\filter\ValidateCodeFilter.java
|
||||
F:\Welcome-2105A\20240521142828\jing-cloud\jing-gateway\src\main\java\com\jing\gateway\config\properties\XssProperties.java
|
||||
F:\Welcome-2105A\20240521142828\jing-cloud\jing-gateway\src\main\java\com\jing\gateway\config\properties\IgnoreWhiteProperties.java
|
||||
F:\Welcome-2105A\20240521142828\jing-cloud\jing-gateway\src\main\java\com\jing\gateway\filter\AuthFilter.java
|
||||
F:\Welcome-2105A\20240521142828\jing-cloud\jing-gateway\src\main\java\com\jing\gateway\filter\BlackListUrlFilter.java
|
||||
F:\Welcome-2105A\20240521142828\jing-cloud\jing-gateway\src\main\java\com\jing\gateway\config\CaptchaConfig.java
|
||||
F:\Welcome-2105A\20240521142828\jing-cloud\jing-gateway\src\main\java\com\jing\gateway\service\impl\ValidateCodeServiceImpl.java
|
||||
F:\Welcome-2105A\20240521142828\jing-cloud\jing-gateway\src\main\java\com\jing\gateway\handler\SwaggerHandler.java
|
||||
F:\Welcome-2105A\20240521142828\jing-cloud\jing-gateway\src\main\java\com\jing\gateway\service\ValidateCodeService.java
|
||||
F:\Welcome-2105A\20240521142828\jing-cloud\jing-gateway\src\main\java\com\jing\gateway\config\RouterFunctionConfiguration.java
|
||||
F:\Welcome-2105A\20240521142828\jing-cloud\jing-gateway\src\main\java\com\jing\gateway\filter\CacheRequestFilter.java
|
||||
F:\Welcome-2105A\20240521142828\jing-cloud\jing-gateway\src\main\java\com\jing\gateway\config\SwaggerProvider.java
|
||||
F:\Welcome-2105A\20240521142828\jing-cloud\jing-gateway\src\main\java\com\jing\gateway\config\GatewayConfig.java
|
||||
F:\Welcome-2105A\20240521142828\jing-cloud\jing-gateway\src\main\java\com\jing\gateway\filter\XssFilter.java
|
||||
F:\Welcome-2105A\20240521142828\jing-cloud\jing-gateway\src\main\java\com\jing\gateway\handler\SentinelFallbackHandler.java
|
Loading…
Reference in New Issue