caojianbin
2 years ago
42 changed files with 1357 additions and 1361 deletions
@ -1,29 +1,29 @@ |
|||||||
package com.ruoyi.gateway; |
package com.yisai.gateway; |
||||||
|
|
||||||
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; |
||||||
|
|
||||||
/** |
/** |
||||||
* 网关启动程序 |
* 网关启动程序 |
||||||
* |
* |
||||||
* @author ruoyi |
* @author ruoyi |
||||||
*/ |
*/ |
||||||
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class }) |
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class }) |
||||||
public class RuoYiGatewayApplication |
public class RuoYiGatewayApplication |
||||||
{ |
{ |
||||||
public static void main(String[] args) |
public static void main(String[] args) |
||||||
{ |
{ |
||||||
SpringApplication.run(RuoYiGatewayApplication.class, args); |
SpringApplication.run(RuoYiGatewayApplication.class, args); |
||||||
System.out.println("(♥◠‿◠)ノ゙ 若依网关启动成功 ლ(´ڡ`ლ)゙ \n" + |
System.out.println("(♥◠‿◠)ノ゙ 若依网关启动成功 ლ(´ڡ`ლ)゙ \n" + |
||||||
" .-------. ____ __ \n" + |
" .-------. ____ __ \n" + |
||||||
" | _ _ \\ \\ \\ / / \n" + |
" | _ _ \\ \\ \\ / / \n" + |
||||||
" | ( ' ) | \\ _. / ' \n" + |
" | ( ' ) | \\ _. / ' \n" + |
||||||
" |(_ o _) / _( )_ .' \n" + |
" |(_ o _) / _( )_ .' \n" + |
||||||
" | (_,_).' __ ___(_ o _)' \n" + |
" | (_,_).' __ ___(_ o _)' \n" + |
||||||
" | |\\ \\ | || |(_,_)' \n" + |
" | |\\ \\ | || |(_,_)' \n" + |
||||||
" | | \\ `' /| `-' / \n" + |
" | | \\ `' /| `-' / \n" + |
||||||
" | | \\ / \\ / \n" + |
" | | \\ / \\ / \n" + |
||||||
" ''-' `'-' `-..-' "); |
" ''-' `'-' `-..-' "); |
||||||
} |
} |
||||||
} |
} |
@ -1,83 +1,83 @@ |
|||||||
package com.ruoyi.gateway.config; |
package com.yisai.gateway.config; |
||||||
|
|
||||||
import java.util.Properties; |
import java.util.Properties; |
||||||
import org.springframework.context.annotation.Bean; |
import org.springframework.context.annotation.Bean; |
||||||
import org.springframework.context.annotation.Configuration; |
import org.springframework.context.annotation.Configuration; |
||||||
import com.google.code.kaptcha.impl.DefaultKaptcha; |
import com.google.code.kaptcha.impl.DefaultKaptcha; |
||||||
import com.google.code.kaptcha.util.Config; |
import com.google.code.kaptcha.util.Config; |
||||||
import static com.google.code.kaptcha.Constants.*; |
import static com.google.code.kaptcha.Constants.*; |
||||||
|
|
||||||
/** |
/** |
||||||
* 验证码配置 |
* 验证码配置 |
||||||
* |
* |
||||||
* @author ruoyi |
* @author ruoyi |
||||||
*/ |
*/ |
||||||
@Configuration |
@Configuration |
||||||
public class CaptchaConfig |
public class CaptchaConfig |
||||||
{ |
{ |
||||||
@Bean(name = "captchaProducer") |
@Bean(name = "captchaProducer") |
||||||
public DefaultKaptcha getKaptchaBean() |
public DefaultKaptcha getKaptchaBean() |
||||||
{ |
{ |
||||||
DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); |
DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); |
||||||
Properties properties = new Properties(); |
Properties properties = new Properties(); |
||||||
// 是否有边框 默认为true 我们可以自己设置yes,no
|
// 是否有边框 默认为true 我们可以自己设置yes,no
|
||||||
properties.setProperty(KAPTCHA_BORDER, "yes"); |
properties.setProperty(KAPTCHA_BORDER, "yes"); |
||||||
// 验证码文本字符颜色 默认为Color.BLACK
|
// 验证码文本字符颜色 默认为Color.BLACK
|
||||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black"); |
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black"); |
||||||
// 验证码图片宽度 默认为200
|
// 验证码图片宽度 默认为200
|
||||||
properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160"); |
properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160"); |
||||||
// 验证码图片高度 默认为50
|
// 验证码图片高度 默认为50
|
||||||
properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60"); |
properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60"); |
||||||
// 验证码文本字符大小 默认为40
|
// 验证码文本字符大小 默认为40
|
||||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38"); |
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38"); |
||||||
// KAPTCHA_SESSION_KEY
|
// KAPTCHA_SESSION_KEY
|
||||||
properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode"); |
properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode"); |
||||||
// 验证码文本字符长度 默认为5
|
// 验证码文本字符长度 默认为5
|
||||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4"); |
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4"); |
||||||
// 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
|
// 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
|
||||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier"); |
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
|
// 图片样式 水纹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"); |
properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy"); |
||||||
Config config = new Config(properties); |
Config config = new Config(properties); |
||||||
defaultKaptcha.setConfig(config); |
defaultKaptcha.setConfig(config); |
||||||
return defaultKaptcha; |
return defaultKaptcha; |
||||||
} |
} |
||||||
|
|
||||||
@Bean(name = "captchaProducerMath") |
@Bean(name = "captchaProducerMath") |
||||||
public DefaultKaptcha getKaptchaBeanMath() |
public DefaultKaptcha getKaptchaBeanMath() |
||||||
{ |
{ |
||||||
DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); |
DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); |
||||||
Properties properties = new Properties(); |
Properties properties = new Properties(); |
||||||
// 是否有边框 默认为true 我们可以自己设置yes,no
|
// 是否有边框 默认为true 我们可以自己设置yes,no
|
||||||
properties.setProperty(KAPTCHA_BORDER, "yes"); |
properties.setProperty(KAPTCHA_BORDER, "yes"); |
||||||
// 边框颜色 默认为Color.BLACK
|
// 边框颜色 默认为Color.BLACK
|
||||||
properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90"); |
properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90"); |
||||||
// 验证码文本字符颜色 默认为Color.BLACK
|
// 验证码文本字符颜色 默认为Color.BLACK
|
||||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue"); |
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue"); |
||||||
// 验证码图片宽度 默认为200
|
// 验证码图片宽度 默认为200
|
||||||
properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160"); |
properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160"); |
||||||
// 验证码图片高度 默认为50
|
// 验证码图片高度 默认为50
|
||||||
properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60"); |
properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60"); |
||||||
// 验证码文本字符大小 默认为40
|
// 验证码文本字符大小 默认为40
|
||||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35"); |
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35"); |
||||||
// KAPTCHA_SESSION_KEY
|
// KAPTCHA_SESSION_KEY
|
||||||
properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath"); |
properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath"); |
||||||
// 验证码文本生成器
|
// 验证码文本生成器
|
||||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.ruoyi.gateway.config.KaptchaTextCreator"); |
properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.ruoyi.gateway.config.KaptchaTextCreator"); |
||||||
// 验证码文本字符间距 默认为2
|
// 验证码文本字符间距 默认为2
|
||||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3"); |
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3"); |
||||||
// 验证码文本字符长度 默认为5
|
// 验证码文本字符长度 默认为5
|
||||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6"); |
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6"); |
||||||
// 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
|
// 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
|
||||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier"); |
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier"); |
||||||
// 验证码噪点颜色 默认为Color.BLACK
|
// 验证码噪点颜色 默认为Color.BLACK
|
||||||
properties.setProperty(KAPTCHA_NOISE_COLOR, "white"); |
properties.setProperty(KAPTCHA_NOISE_COLOR, "white"); |
||||||
// 干扰实现类
|
// 干扰实现类
|
||||||
properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise"); |
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
|
// 图片样式 水纹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"); |
properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy"); |
||||||
Config config = new Config(properties); |
Config config = new Config(properties); |
||||||
defaultKaptcha.setConfig(config); |
defaultKaptcha.setConfig(config); |
||||||
return defaultKaptcha; |
return defaultKaptcha; |
||||||
} |
} |
||||||
} |
} |
@ -1,23 +1,23 @@ |
|||||||
package com.ruoyi.gateway.config; |
package com.yisai.gateway.config; |
||||||
|
|
||||||
import org.springframework.context.annotation.Bean; |
import com.yisai.gateway.handler.SentinelFallbackHandler; |
||||||
import org.springframework.context.annotation.Configuration; |
import org.springframework.context.annotation.Bean; |
||||||
import org.springframework.core.Ordered; |
import org.springframework.context.annotation.Configuration; |
||||||
import org.springframework.core.annotation.Order; |
import org.springframework.core.Ordered; |
||||||
import com.ruoyi.gateway.handler.SentinelFallbackHandler; |
import org.springframework.core.annotation.Order; |
||||||
|
|
||||||
/** |
/** |
||||||
* 网关限流配置 |
* 网关限流配置 |
||||||
* |
* |
||||||
* @author ruoyi |
* @author ruoyi |
||||||
*/ |
*/ |
||||||
@Configuration |
@Configuration |
||||||
public class GatewayConfig |
public class GatewayConfig |
||||||
{ |
{ |
||||||
@Bean |
@Bean |
||||||
@Order(Ordered.HIGHEST_PRECEDENCE) |
@Order(Ordered.HIGHEST_PRECEDENCE) |
||||||
public SentinelFallbackHandler sentinelGatewayExceptionHandler() |
public SentinelFallbackHandler sentinelGatewayExceptionHandler() |
||||||
{ |
{ |
||||||
return new SentinelFallbackHandler(); |
return new SentinelFallbackHandler(); |
||||||
} |
} |
||||||
} |
} |
@ -1,75 +1,75 @@ |
|||||||
package com.ruoyi.gateway.config; |
package com.yisai.gateway.config; |
||||||
|
|
||||||
import java.util.Random; |
import java.util.Random; |
||||||
import com.google.code.kaptcha.text.impl.DefaultTextCreator; |
import com.google.code.kaptcha.text.impl.DefaultTextCreator; |
||||||
|
|
||||||
/** |
/** |
||||||
* 验证码文本生成器 |
* 验证码文本生成器 |
||||||
* |
* |
||||||
* @author ruoyi |
* @author ruoyi |
||||||
*/ |
*/ |
||||||
public class KaptchaTextCreator extends DefaultTextCreator |
public class KaptchaTextCreator extends DefaultTextCreator |
||||||
{ |
{ |
||||||
private static final String[] CNUMBERS = "0,1,2,3,4,5,6,7,8,9,10".split(","); |
private static final String[] CNUMBERS = "0,1,2,3,4,5,6,7,8,9,10".split(","); |
||||||
|
|
||||||
@Override |
@Override |
||||||
public String getText() |
public String getText() |
||||||
{ |
{ |
||||||
Integer result = 0; |
Integer result = 0; |
||||||
Random random = new Random(); |
Random random = new Random(); |
||||||
int x = random.nextInt(10); |
int x = random.nextInt(10); |
||||||
int y = random.nextInt(10); |
int y = random.nextInt(10); |
||||||
StringBuilder suChinese = new StringBuilder(); |
StringBuilder suChinese = new StringBuilder(); |
||||||
int randomoperands = (int) Math.round(Math.random() * 2); |
int randomoperands = (int) Math.round(Math.random() * 2); |
||||||
if (randomoperands == 0) |
if (randomoperands == 0) |
||||||
{ |
{ |
||||||
result = x * y; |
result = x * y; |
||||||
suChinese.append(CNUMBERS[x]); |
suChinese.append(CNUMBERS[x]); |
||||||
suChinese.append("*"); |
suChinese.append("*"); |
||||||
suChinese.append(CNUMBERS[y]); |
suChinese.append(CNUMBERS[y]); |
||||||
} |
} |
||||||
else if (randomoperands == 1) |
else if (randomoperands == 1) |
||||||
{ |
{ |
||||||
if (!(x == 0) && y % x == 0) |
if (!(x == 0) && y % x == 0) |
||||||
{ |
{ |
||||||
result = y / x; |
result = y / x; |
||||||
suChinese.append(CNUMBERS[y]); |
suChinese.append(CNUMBERS[y]); |
||||||
suChinese.append("/"); |
suChinese.append("/"); |
||||||
suChinese.append(CNUMBERS[x]); |
suChinese.append(CNUMBERS[x]); |
||||||
} |
} |
||||||
else |
else |
||||||
{ |
{ |
||||||
result = x + y; |
result = x + y; |
||||||
suChinese.append(CNUMBERS[x]); |
suChinese.append(CNUMBERS[x]); |
||||||
suChinese.append("+"); |
suChinese.append("+"); |
||||||
suChinese.append(CNUMBERS[y]); |
suChinese.append(CNUMBERS[y]); |
||||||
} |
} |
||||||
} |
} |
||||||
else if (randomoperands == 2) |
else if (randomoperands == 2) |
||||||
{ |
{ |
||||||
if (x >= y) |
if (x >= y) |
||||||
{ |
{ |
||||||
result = x - y; |
result = x - y; |
||||||
suChinese.append(CNUMBERS[x]); |
suChinese.append(CNUMBERS[x]); |
||||||
suChinese.append("-"); |
suChinese.append("-"); |
||||||
suChinese.append(CNUMBERS[y]); |
suChinese.append(CNUMBERS[y]); |
||||||
} |
} |
||||||
else |
else |
||||||
{ |
{ |
||||||
result = y - x; |
result = y - x; |
||||||
suChinese.append(CNUMBERS[y]); |
suChinese.append(CNUMBERS[y]); |
||||||
suChinese.append("-"); |
suChinese.append("-"); |
||||||
suChinese.append(CNUMBERS[x]); |
suChinese.append(CNUMBERS[x]); |
||||||
} |
} |
||||||
} |
} |
||||||
else |
else |
||||||
{ |
{ |
||||||
result = x + y; |
result = x + y; |
||||||
suChinese.append(CNUMBERS[x]); |
suChinese.append(CNUMBERS[x]); |
||||||
suChinese.append("+"); |
suChinese.append("+"); |
||||||
suChinese.append(CNUMBERS[y]); |
suChinese.append(CNUMBERS[y]); |
||||||
} |
} |
||||||
suChinese.append("=?@" + result); |
suChinese.append("=?@" + result); |
||||||
return suChinese.toString(); |
return suChinese.toString(); |
||||||
} |
} |
||||||
} |
} |
@ -1,31 +1,31 @@ |
|||||||
package com.ruoyi.gateway.config; |
package com.yisai.gateway.config; |
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired; |
import com.yisai.gateway.handler.ValidateCodeHandler; |
||||||
import org.springframework.context.annotation.Bean; |
import org.springframework.beans.factory.annotation.Autowired; |
||||||
import org.springframework.context.annotation.Configuration; |
import org.springframework.context.annotation.Bean; |
||||||
import org.springframework.http.MediaType; |
import org.springframework.context.annotation.Configuration; |
||||||
import org.springframework.web.reactive.function.server.RequestPredicates; |
import org.springframework.http.MediaType; |
||||||
import org.springframework.web.reactive.function.server.RouterFunction; |
import org.springframework.web.reactive.function.server.RequestPredicates; |
||||||
import org.springframework.web.reactive.function.server.RouterFunctions; |
import org.springframework.web.reactive.function.server.RouterFunction; |
||||||
import com.ruoyi.gateway.handler.ValidateCodeHandler; |
import org.springframework.web.reactive.function.server.RouterFunctions; |
||||||
|
|
||||||
/** |
/** |
||||||
* 路由配置信息 |
* 路由配置信息 |
||||||
* |
* |
||||||
* @author ruoyi |
* @author ruoyi |
||||||
*/ |
*/ |
||||||
@Configuration |
@Configuration |
||||||
public class RouterFunctionConfiguration |
public class RouterFunctionConfiguration |
||||||
{ |
{ |
||||||
@Autowired |
@Autowired |
||||||
private ValidateCodeHandler validateCodeHandler; |
private ValidateCodeHandler validateCodeHandler; |
||||||
|
|
||||||
@SuppressWarnings("rawtypes") |
@SuppressWarnings("rawtypes") |
||||||
@Bean |
@Bean |
||||||
public RouterFunction routerFunction() |
public RouterFunction routerFunction() |
||||||
{ |
{ |
||||||
return RouterFunctions.route( |
return RouterFunctions.route( |
||||||
RequestPredicates.GET("/code").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), |
RequestPredicates.GET("/code").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), |
||||||
validateCodeHandler); |
validateCodeHandler); |
||||||
} |
} |
||||||
} |
} |
@ -1,79 +1,79 @@ |
|||||||
package com.ruoyi.gateway.config; |
package com.yisai.gateway.config; |
||||||
|
|
||||||
import java.util.ArrayList; |
import java.util.ArrayList; |
||||||
import java.util.List; |
import java.util.List; |
||||||
import org.springframework.beans.factory.annotation.Autowired; |
import org.springframework.beans.factory.annotation.Autowired; |
||||||
import org.springframework.cloud.gateway.config.GatewayProperties; |
import org.springframework.cloud.gateway.config.GatewayProperties; |
||||||
import org.springframework.cloud.gateway.route.RouteLocator; |
import org.springframework.cloud.gateway.route.RouteLocator; |
||||||
import org.springframework.cloud.gateway.support.NameUtils; |
import org.springframework.cloud.gateway.support.NameUtils; |
||||||
import org.springframework.context.annotation.Lazy; |
import org.springframework.context.annotation.Lazy; |
||||||
import org.springframework.stereotype.Component; |
import org.springframework.stereotype.Component; |
||||||
import org.springframework.web.reactive.config.ResourceHandlerRegistry; |
import org.springframework.web.reactive.config.ResourceHandlerRegistry; |
||||||
import org.springframework.web.reactive.config.WebFluxConfigurer; |
import org.springframework.web.reactive.config.WebFluxConfigurer; |
||||||
import springfox.documentation.swagger.web.SwaggerResource; |
import springfox.documentation.swagger.web.SwaggerResource; |
||||||
import springfox.documentation.swagger.web.SwaggerResourcesProvider; |
import springfox.documentation.swagger.web.SwaggerResourcesProvider; |
||||||
|
|
||||||
/** |
/** |
||||||
* 聚合系统接口 |
* 聚合系统接口 |
||||||
* |
* |
||||||
* @author ruoyi |
* @author ruoyi |
||||||
*/ |
*/ |
||||||
@Component |
@Component |
||||||
public class SwaggerProvider implements SwaggerResourcesProvider, WebFluxConfigurer |
public class SwaggerProvider implements SwaggerResourcesProvider, WebFluxConfigurer |
||||||
{ |
{ |
||||||
/** |
/** |
||||||
* Swagger2默认的url后缀 |
* Swagger2默认的url后缀 |
||||||
*/ |
*/ |
||||||
public static final String SWAGGER2URL = "/v2/api-docs"; |
public static final String SWAGGER2URL = "/v2/api-docs"; |
||||||
|
|
||||||
/** |
/** |
||||||
* 网关路由 |
* 网关路由 |
||||||
*/ |
*/ |
||||||
@Lazy |
@Lazy |
||||||
@Autowired |
@Autowired |
||||||
private RouteLocator routeLocator; |
private RouteLocator routeLocator; |
||||||
|
|
||||||
@Autowired |
@Autowired |
||||||
private GatewayProperties gatewayProperties; |
private GatewayProperties gatewayProperties; |
||||||
|
|
||||||
/** |
/** |
||||||
* 聚合其他服务接口 |
* 聚合其他服务接口 |
||||||
* |
* |
||||||
* @return |
* @return |
||||||
*/ |
*/ |
||||||
@Override |
@Override |
||||||
public List<SwaggerResource> get() |
public List<SwaggerResource> get() |
||||||
{ |
{ |
||||||
List<SwaggerResource> resourceList = new ArrayList<>(); |
List<SwaggerResource> resourceList = new ArrayList<>(); |
||||||
List<String> routes = new ArrayList<>(); |
List<String> routes = new ArrayList<>(); |
||||||
// 获取网关中配置的route
|
// 获取网关中配置的route
|
||||||
routeLocator.getRoutes().subscribe(route -> routes.add(route.getId())); |
routeLocator.getRoutes().subscribe(route -> routes.add(route.getId())); |
||||||
gatewayProperties.getRoutes().stream() |
gatewayProperties.getRoutes().stream() |
||||||
.filter(routeDefinition -> routes |
.filter(routeDefinition -> routes |
||||||
.contains(routeDefinition.getId())) |
.contains(routeDefinition.getId())) |
||||||
.forEach(routeDefinition -> routeDefinition.getPredicates().stream() |
.forEach(routeDefinition -> routeDefinition.getPredicates().stream() |
||||||
.filter(predicateDefinition -> "Path".equalsIgnoreCase(predicateDefinition.getName())) |
.filter(predicateDefinition -> "Path".equalsIgnoreCase(predicateDefinition.getName())) |
||||||
.filter(predicateDefinition -> !"ruoyi-auth".equalsIgnoreCase(routeDefinition.getId())) |
.filter(predicateDefinition -> !"ruoyi-auth".equalsIgnoreCase(routeDefinition.getId())) |
||||||
.forEach(predicateDefinition -> resourceList |
.forEach(predicateDefinition -> resourceList |
||||||
.add(swaggerResource(routeDefinition.getId(), predicateDefinition.getArgs() |
.add(swaggerResource(routeDefinition.getId(), predicateDefinition.getArgs() |
||||||
.get(NameUtils.GENERATED_NAME_PREFIX + "0").replace("/**", SWAGGER2URL))))); |
.get(NameUtils.GENERATED_NAME_PREFIX + "0").replace("/**", SWAGGER2URL))))); |
||||||
return resourceList; |
return resourceList; |
||||||
} |
} |
||||||
|
|
||||||
private SwaggerResource swaggerResource(String name, String location) |
private SwaggerResource swaggerResource(String name, String location) |
||||||
{ |
{ |
||||||
SwaggerResource swaggerResource = new SwaggerResource(); |
SwaggerResource swaggerResource = new SwaggerResource(); |
||||||
swaggerResource.setName(name); |
swaggerResource.setName(name); |
||||||
swaggerResource.setLocation(location); |
swaggerResource.setLocation(location); |
||||||
swaggerResource.setSwaggerVersion("2.0"); |
swaggerResource.setSwaggerVersion("2.0"); |
||||||
return swaggerResource; |
return swaggerResource; |
||||||
} |
} |
||||||
|
|
||||||
@Override |
@Override |
||||||
public void addResourceHandlers(ResourceHandlerRegistry registry) |
public void addResourceHandlers(ResourceHandlerRegistry registry) |
||||||
{ |
{ |
||||||
/** swagger-ui 地址 */ |
/** swagger-ui 地址 */ |
||||||
registry.addResourceHandler("/swagger-ui/**") |
registry.addResourceHandler("/swagger-ui/**") |
||||||
.addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/"); |
.addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/"); |
||||||
} |
} |
||||||
} |
} |
@ -1,46 +1,46 @@ |
|||||||
package com.ruoyi.gateway.config.properties; |
package com.yisai.gateway.config.properties; |
||||||
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties; |
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||||
import org.springframework.cloud.context.config.annotation.RefreshScope; |
import org.springframework.cloud.context.config.annotation.RefreshScope; |
||||||
import org.springframework.context.annotation.Configuration; |
import org.springframework.context.annotation.Configuration; |
||||||
|
|
||||||
/** |
/** |
||||||
* 验证码配置 |
* 验证码配置 |
||||||
* |
* |
||||||
* @author ruoyi |
* @author ruoyi |
||||||
*/ |
*/ |
||||||
@Configuration |
@Configuration |
||||||
@RefreshScope |
@RefreshScope |
||||||
@ConfigurationProperties(prefix = "security.captcha") |
@ConfigurationProperties(prefix = "security.captcha") |
||||||
public class CaptchaProperties |
public class CaptchaProperties |
||||||
{ |
{ |
||||||
/** |
/** |
||||||
* 验证码开关 |
* 验证码开关 |
||||||
*/ |
*/ |
||||||
private Boolean enabled; |
private Boolean enabled; |
||||||
|
|
||||||
/** |
/** |
||||||
* 验证码类型(math 数组计算 char 字符) |
* 验证码类型(math 数组计算 char 字符) |
||||||
*/ |
*/ |
||||||
private String type; |
private String type; |
||||||
|
|
||||||
public Boolean getEnabled() |
public Boolean getEnabled() |
||||||
{ |
{ |
||||||
return enabled; |
return enabled; |
||||||
} |
} |
||||||
|
|
||||||
public void setEnabled(Boolean enabled) |
public void setEnabled(Boolean enabled) |
||||||
{ |
{ |
||||||
this.enabled = enabled; |
this.enabled = enabled; |
||||||
} |
} |
||||||
|
|
||||||
public String getType() |
public String getType() |
||||||
{ |
{ |
||||||
return type; |
return type; |
||||||
} |
} |
||||||
|
|
||||||
public void setType(String type) |
public void setType(String type) |
||||||
{ |
{ |
||||||
this.type = type; |
this.type = type; |
||||||
} |
} |
||||||
} |
} |
@ -1,33 +1,33 @@ |
|||||||
package com.ruoyi.gateway.config.properties; |
package com.yisai.gateway.config.properties; |
||||||
|
|
||||||
import java.util.ArrayList; |
import java.util.ArrayList; |
||||||
import java.util.List; |
import java.util.List; |
||||||
import org.springframework.boot.context.properties.ConfigurationProperties; |
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||||
import org.springframework.cloud.context.config.annotation.RefreshScope; |
import org.springframework.cloud.context.config.annotation.RefreshScope; |
||||||
import org.springframework.context.annotation.Configuration; |
import org.springframework.context.annotation.Configuration; |
||||||
|
|
||||||
/** |
/** |
||||||
* 放行白名单配置 |
* 放行白名单配置 |
||||||
* |
* |
||||||
* @author ruoyi |
* @author ruoyi |
||||||
*/ |
*/ |
||||||
@Configuration |
@Configuration |
||||||
@RefreshScope |
@RefreshScope |
||||||
@ConfigurationProperties(prefix = "security.ignore") |
@ConfigurationProperties(prefix = "security.ignore") |
||||||
public class IgnoreWhiteProperties |
public class IgnoreWhiteProperties |
||||||
{ |
{ |
||||||
/** |
/** |
||||||
* 放行白名单配置,网关不校验此处的白名单 |
* 放行白名单配置,网关不校验此处的白名单 |
||||||
*/ |
*/ |
||||||
private List<String> whites = new ArrayList<>(); |
private List<String> whites = new ArrayList<>(); |
||||||
|
|
||||||
public List<String> getWhites() |
public List<String> getWhites() |
||||||
{ |
{ |
||||||
return whites; |
return whites; |
||||||
} |
} |
||||||
|
|
||||||
public void setWhites(List<String> whites) |
public void setWhites(List<String> whites) |
||||||
{ |
{ |
||||||
this.whites = whites; |
this.whites = whites; |
||||||
} |
} |
||||||
} |
} |
@ -1,48 +1,48 @@ |
|||||||
package com.ruoyi.gateway.config.properties; |
package com.yisai.gateway.config.properties; |
||||||
|
|
||||||
import java.util.ArrayList; |
import java.util.ArrayList; |
||||||
import java.util.List; |
import java.util.List; |
||||||
import org.springframework.boot.context.properties.ConfigurationProperties; |
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||||
import org.springframework.cloud.context.config.annotation.RefreshScope; |
import org.springframework.cloud.context.config.annotation.RefreshScope; |
||||||
import org.springframework.context.annotation.Configuration; |
import org.springframework.context.annotation.Configuration; |
||||||
|
|
||||||
/** |
/** |
||||||
* XSS跨站脚本配置 |
* XSS跨站脚本配置 |
||||||
* |
* |
||||||
* @author ruoyi |
* @author ruoyi |
||||||
*/ |
*/ |
||||||
@Configuration |
@Configuration |
||||||
@RefreshScope |
@RefreshScope |
||||||
@ConfigurationProperties(prefix = "security.xss") |
@ConfigurationProperties(prefix = "security.xss") |
||||||
public class XssProperties |
public class XssProperties |
||||||
{ |
{ |
||||||
/** |
/** |
||||||
* Xss开关 |
* Xss开关 |
||||||
*/ |
*/ |
||||||
private Boolean enabled; |
private Boolean enabled; |
||||||
|
|
||||||
/** |
/** |
||||||
* 排除路径 |
* 排除路径 |
||||||
*/ |
*/ |
||||||
private List<String> excludeUrls = new ArrayList<>(); |
private List<String> excludeUrls = new ArrayList<>(); |
||||||
|
|
||||||
public Boolean getEnabled() |
public Boolean getEnabled() |
||||||
{ |
{ |
||||||
return enabled; |
return enabled; |
||||||
} |
} |
||||||
|
|
||||||
public void setEnabled(Boolean enabled) |
public void setEnabled(Boolean enabled) |
||||||
{ |
{ |
||||||
this.enabled = enabled; |
this.enabled = enabled; |
||||||
} |
} |
||||||
|
|
||||||
public List<String> getExcludeUrls() |
public List<String> getExcludeUrls() |
||||||
{ |
{ |
||||||
return excludeUrls; |
return excludeUrls; |
||||||
} |
} |
||||||
|
|
||||||
public void setExcludeUrls(List<String> excludeUrls) |
public void setExcludeUrls(List<String> excludeUrls) |
||||||
{ |
{ |
||||||
this.excludeUrls = excludeUrls; |
this.excludeUrls = excludeUrls; |
||||||
} |
} |
||||||
} |
} |
@ -1,14 +1,9 @@ |
|||||||
package com.ruoyi.gateway.constant; |
package com.yisai.gateway.constant; |
||||||
|
|
||||||
import com.ruoyi.gateway.filter.AuthFilter; |
|
||||||
import org.slf4j.LoggerFactory; |
import org.slf4j.LoggerFactory; |
||||||
import org.springframework.http.server.reactive.ServerHttpRequest; |
import org.springframework.http.server.reactive.ServerHttpRequest; |
||||||
import org.springframework.web.server.ServerWebExchange; |
import org.springframework.web.server.ServerWebExchange; |
||||||
|
|
||||||
import java.util.List; |
|
||||||
import java.util.Locale; |
|
||||||
import java.util.logging.Logger; |
|
||||||
|
|
||||||
public class MessagesConstant { |
public class MessagesConstant { |
||||||
private static final org.slf4j.Logger log = LoggerFactory.getLogger(MessagesConstant.class); |
private static final org.slf4j.Logger log = LoggerFactory.getLogger(MessagesConstant.class); |
||||||
/**令牌不能为空*/ |
/**令牌不能为空*/ |
@ -1,67 +1,67 @@ |
|||||||
package com.ruoyi.gateway.filter; |
package com.yisai.gateway.filter; |
||||||
|
|
||||||
import java.util.ArrayList; |
import java.util.ArrayList; |
||||||
import java.util.List; |
import java.util.List; |
||||||
import java.util.regex.Pattern; |
import java.util.regex.Pattern; |
||||||
|
|
||||||
import com.ruoyi.gateway.constant.MessagesConstant; |
import com.yisai.gateway.constant.MessagesConstant; |
||||||
import org.springframework.cloud.gateway.filter.GatewayFilter; |
import org.springframework.cloud.gateway.filter.GatewayFilter; |
||||||
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; |
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; |
||||||
import org.springframework.stereotype.Component; |
import org.springframework.stereotype.Component; |
||||||
import com.ruoyi.common.core.utils.ServletUtils; |
import com.ruoyi.common.core.utils.ServletUtils; |
||||||
|
|
||||||
/** |
/** |
||||||
* 黑名单过滤器 |
* 黑名单过滤器 |
||||||
* |
* |
||||||
* @author ruoyi |
* @author ruoyi |
||||||
*/ |
*/ |
||||||
@Component |
@Component |
||||||
public class BlackListUrlFilter extends AbstractGatewayFilterFactory<BlackListUrlFilter.Config> |
public class BlackListUrlFilter extends AbstractGatewayFilterFactory<BlackListUrlFilter.Config> |
||||||
{ |
{ |
||||||
@Override |
@Override |
||||||
public GatewayFilter apply(Config config) |
public GatewayFilter apply(Config config) |
||||||
{ |
{ |
||||||
return (exchange, chain) -> { |
return (exchange, chain) -> { |
||||||
|
|
||||||
String url = exchange.getRequest().getURI().getPath(); |
String url = exchange.getRequest().getURI().getPath(); |
||||||
if (config.matchBlacklist(url)) |
if (config.matchBlacklist(url)) |
||||||
{ |
{ |
||||||
return ServletUtils.webFluxResponseWriter(exchange.getResponse(), MessagesConstant.getMessages(exchange,MessagesConstant.MESSAGES_REQUEST_ADDRESS_ZH,MessagesConstant.MESSAGES_REQUEST_ADDRESS_EN)); |
return ServletUtils.webFluxResponseWriter(exchange.getResponse(), MessagesConstant.getMessages(exchange,MessagesConstant.MESSAGES_REQUEST_ADDRESS_ZH,MessagesConstant.MESSAGES_REQUEST_ADDRESS_EN)); |
||||||
} |
} |
||||||
|
|
||||||
return chain.filter(exchange); |
return chain.filter(exchange); |
||||||
}; |
}; |
||||||
} |
} |
||||||
|
|
||||||
public BlackListUrlFilter() |
public BlackListUrlFilter() |
||||||
{ |
{ |
||||||
super(Config.class); |
super(Config.class); |
||||||
} |
} |
||||||
|
|
||||||
public static class Config |
public static class Config |
||||||
{ |
{ |
||||||
private List<String> blacklistUrl; |
private List<String> blacklistUrl; |
||||||
|
|
||||||
private List<Pattern> blacklistUrlPattern = new ArrayList<>(); |
private List<Pattern> blacklistUrlPattern = new ArrayList<>(); |
||||||
|
|
||||||
public boolean matchBlacklist(String url) |
public boolean matchBlacklist(String url) |
||||||
{ |
{ |
||||||
return !blacklistUrlPattern.isEmpty() && blacklistUrlPattern.stream().anyMatch(p -> p.matcher(url).find()); |
return !blacklistUrlPattern.isEmpty() && blacklistUrlPattern.stream().anyMatch(p -> p.matcher(url).find()); |
||||||
} |
} |
||||||
|
|
||||||
public List<String> getBlacklistUrl() |
public List<String> getBlacklistUrl() |
||||||
{ |
{ |
||||||
return blacklistUrl; |
return blacklistUrl; |
||||||
} |
} |
||||||
|
|
||||||
public void setBlacklistUrl(List<String> blacklistUrl) |
public void setBlacklistUrl(List<String> blacklistUrl) |
||||||
{ |
{ |
||||||
this.blacklistUrl = blacklistUrl; |
this.blacklistUrl = blacklistUrl; |
||||||
this.blacklistUrlPattern.clear(); |
this.blacklistUrlPattern.clear(); |
||||||
this.blacklistUrl.forEach(url -> { |
this.blacklistUrl.forEach(url -> { |
||||||
this.blacklistUrlPattern.add(Pattern.compile(url.replaceAll("\\*\\*", "(.*?)"), Pattern.CASE_INSENSITIVE)); |
this.blacklistUrlPattern.add(Pattern.compile(url.replaceAll("\\*\\*", "(.*?)"), Pattern.CASE_INSENSITIVE)); |
||||||
}); |
}); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
} |
} |
@ -1,4 +1,4 @@ |
|||||||
package com.ruoyi.gateway.filter; |
package com.yisai.gateway.filter; |
||||||
|
|
||||||
import java.util.Collections; |
import java.util.Collections; |
||||||
import java.util.List; |
import java.util.List; |
@ -1,79 +1,80 @@ |
|||||||
package com.ruoyi.gateway.filter; |
package com.yisai.gateway.filter; |
||||||
|
|
||||||
import java.nio.CharBuffer; |
import java.nio.CharBuffer; |
||||||
import java.nio.charset.StandardCharsets; |
import java.nio.charset.StandardCharsets; |
||||||
import java.util.concurrent.atomic.AtomicReference; |
import java.util.concurrent.atomic.AtomicReference; |
||||||
import org.springframework.beans.factory.annotation.Autowired; |
|
||||||
import org.springframework.cloud.gateway.filter.GatewayFilter; |
import com.yisai.gateway.config.properties.CaptchaProperties; |
||||||
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; |
import com.yisai.gateway.service.ValidateCodeService; |
||||||
import org.springframework.core.io.buffer.DataBuffer; |
import org.springframework.beans.factory.annotation.Autowired; |
||||||
import org.springframework.core.io.buffer.DataBufferUtils; |
import org.springframework.cloud.gateway.filter.GatewayFilter; |
||||||
import org.springframework.http.server.reactive.ServerHttpRequest; |
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; |
||||||
import org.springframework.stereotype.Component; |
import org.springframework.core.io.buffer.DataBuffer; |
||||||
import com.alibaba.fastjson2.JSON; |
import org.springframework.core.io.buffer.DataBufferUtils; |
||||||
import com.alibaba.fastjson2.JSONObject; |
import org.springframework.http.server.reactive.ServerHttpRequest; |
||||||
import com.ruoyi.common.core.utils.ServletUtils; |
import org.springframework.stereotype.Component; |
||||||
import com.ruoyi.common.core.utils.StringUtils; |
import com.alibaba.fastjson2.JSON; |
||||||
import com.ruoyi.gateway.config.properties.CaptchaProperties; |
import com.alibaba.fastjson2.JSONObject; |
||||||
import com.ruoyi.gateway.service.ValidateCodeService; |
import com.ruoyi.common.core.utils.ServletUtils; |
||||||
import reactor.core.publisher.Flux; |
import com.ruoyi.common.core.utils.StringUtils; |
||||||
|
import reactor.core.publisher.Flux; |
||||||
/** |
|
||||||
* 验证码过滤器 |
/** |
||||||
* |
* 验证码过滤器 |
||||||
* @author ruoyi |
* |
||||||
*/ |
* @author ruoyi |
||||||
@Component |
*/ |
||||||
public class ValidateCodeFilter extends AbstractGatewayFilterFactory<Object> |
@Component |
||||||
{ |
public class ValidateCodeFilter extends AbstractGatewayFilterFactory<Object> |
||||||
private final static String[] VALIDATE_URL = new String[] { "/auth/login", "/auth/register" }; |
{ |
||||||
|
private final static String[] VALIDATE_URL = new String[] { "/auth/login", "/auth/register" }; |
||||||
@Autowired |
|
||||||
private ValidateCodeService validateCodeService; |
@Autowired |
||||||
|
private ValidateCodeService validateCodeService; |
||||||
@Autowired |
|
||||||
private CaptchaProperties captchaProperties; |
@Autowired |
||||||
|
private CaptchaProperties captchaProperties; |
||||||
private static final String CODE = "code"; |
|
||||||
|
private static final String CODE = "code"; |
||||||
private static final String UUID = "uuid"; |
|
||||||
|
private static final String UUID = "uuid"; |
||||||
@Override |
|
||||||
public GatewayFilter apply(Object config) |
@Override |
||||||
{ |
public GatewayFilter apply(Object config) |
||||||
return (exchange, chain) -> { |
{ |
||||||
ServerHttpRequest request = exchange.getRequest(); |
return (exchange, chain) -> { |
||||||
|
ServerHttpRequest request = exchange.getRequest(); |
||||||
// 非登录/注册请求或验证码关闭,不处理
|
|
||||||
if (!StringUtils.containsAnyIgnoreCase(request.getURI().getPath(), VALIDATE_URL) || !captchaProperties.getEnabled()) |
// 非登录/注册请求或验证码关闭,不处理
|
||||||
{ |
if (!StringUtils.containsAnyIgnoreCase(request.getURI().getPath(), VALIDATE_URL) || !captchaProperties.getEnabled()) |
||||||
return chain.filter(exchange); |
{ |
||||||
} |
return chain.filter(exchange); |
||||||
|
} |
||||||
try |
|
||||||
{ |
try |
||||||
String rspStr = resolveBodyFromRequest(request); |
{ |
||||||
JSONObject obj = JSON.parseObject(rspStr); |
String rspStr = resolveBodyFromRequest(request); |
||||||
validateCodeService.checkCaptcha(obj.getString(CODE), obj.getString(UUID)); |
JSONObject obj = JSON.parseObject(rspStr); |
||||||
} |
validateCodeService.checkCaptcha(obj.getString(CODE), obj.getString(UUID)); |
||||||
catch (Exception e) |
} |
||||||
{ |
catch (Exception e) |
||||||
return ServletUtils.webFluxResponseWriter(exchange.getResponse(), e.getMessage()); |
{ |
||||||
} |
return ServletUtils.webFluxResponseWriter(exchange.getResponse(), e.getMessage()); |
||||||
return chain.filter(exchange); |
} |
||||||
}; |
return chain.filter(exchange); |
||||||
} |
}; |
||||||
|
} |
||||||
private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest) |
|
||||||
{ |
private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest) |
||||||
// 获取请求体
|
{ |
||||||
Flux<DataBuffer> body = serverHttpRequest.getBody(); |
// 获取请求体
|
||||||
AtomicReference<String> bodyRef = new AtomicReference<>(); |
Flux<DataBuffer> body = serverHttpRequest.getBody(); |
||||||
body.subscribe(buffer -> { |
AtomicReference<String> bodyRef = new AtomicReference<>(); |
||||||
CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer()); |
body.subscribe(buffer -> { |
||||||
DataBufferUtils.release(buffer); |
CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer()); |
||||||
bodyRef.set(charBuffer.toString()); |
DataBufferUtils.release(buffer); |
||||||
}); |
bodyRef.set(charBuffer.toString()); |
||||||
return bodyRef.get(); |
}); |
||||||
} |
return bodyRef.get(); |
||||||
} |
} |
||||||
|
} |
@ -1,124 +1,124 @@ |
|||||||
package com.ruoyi.gateway.filter; |
package com.yisai.gateway.filter; |
||||||
|
|
||||||
import java.nio.charset.StandardCharsets; |
import java.nio.charset.StandardCharsets; |
||||||
import org.springframework.beans.factory.annotation.Autowired; |
import org.springframework.beans.factory.annotation.Autowired; |
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
||||||
import org.springframework.cloud.gateway.filter.GatewayFilterChain; |
import org.springframework.cloud.gateway.filter.GatewayFilterChain; |
||||||
import org.springframework.cloud.gateway.filter.GlobalFilter; |
import org.springframework.cloud.gateway.filter.GlobalFilter; |
||||||
import org.springframework.core.Ordered; |
import org.springframework.core.Ordered; |
||||||
import org.springframework.core.io.buffer.DataBuffer; |
import org.springframework.core.io.buffer.DataBuffer; |
||||||
import org.springframework.core.io.buffer.DataBufferFactory; |
import org.springframework.core.io.buffer.DataBufferFactory; |
||||||
import org.springframework.core.io.buffer.DataBufferUtils; |
import org.springframework.core.io.buffer.DataBufferUtils; |
||||||
import org.springframework.core.io.buffer.DefaultDataBufferFactory; |
import org.springframework.core.io.buffer.DefaultDataBufferFactory; |
||||||
import org.springframework.core.io.buffer.NettyDataBufferFactory; |
import org.springframework.core.io.buffer.NettyDataBufferFactory; |
||||||
import org.springframework.http.HttpHeaders; |
import org.springframework.http.HttpHeaders; |
||||||
import org.springframework.http.HttpMethod; |
import org.springframework.http.HttpMethod; |
||||||
import org.springframework.http.MediaType; |
import org.springframework.http.MediaType; |
||||||
import org.springframework.http.server.reactive.ServerHttpRequest; |
import org.springframework.http.server.reactive.ServerHttpRequest; |
||||||
import org.springframework.http.server.reactive.ServerHttpRequestDecorator; |
import org.springframework.http.server.reactive.ServerHttpRequestDecorator; |
||||||
import org.springframework.stereotype.Component; |
import org.springframework.stereotype.Component; |
||||||
import org.springframework.web.server.ServerWebExchange; |
import org.springframework.web.server.ServerWebExchange; |
||||||
import com.ruoyi.common.core.utils.StringUtils; |
import com.ruoyi.common.core.utils.StringUtils; |
||||||
import com.ruoyi.common.core.utils.html.EscapeUtil; |
import com.ruoyi.common.core.utils.html.EscapeUtil; |
||||||
import com.ruoyi.gateway.config.properties.XssProperties; |
import com.yisai.gateway.config.properties.XssProperties; |
||||||
import io.netty.buffer.ByteBufAllocator; |
import io.netty.buffer.ByteBufAllocator; |
||||||
import reactor.core.publisher.Flux; |
import reactor.core.publisher.Flux; |
||||||
import reactor.core.publisher.Mono; |
import reactor.core.publisher.Mono; |
||||||
|
|
||||||
/** |
/** |
||||||
* 跨站脚本过滤器 |
* 跨站脚本过滤器 |
||||||
* |
* |
||||||
* @author ruoyi |
* @author ruoyi |
||||||
*/ |
*/ |
||||||
@Component |
@Component |
||||||
@ConditionalOnProperty(value = "security.xss.enabled", havingValue = "true") |
@ConditionalOnProperty(value = "security.xss.enabled", havingValue = "true") |
||||||
public class XssFilter implements GlobalFilter, Ordered |
public class XssFilter implements GlobalFilter, Ordered |
||||||
{ |
{ |
||||||
// 跨站脚本的 xss 配置,nacos自行添加
|
// 跨站脚本的 xss 配置,nacos自行添加
|
||||||
@Autowired |
@Autowired |
||||||
private XssProperties xss; |
private XssProperties xss; |
||||||
|
|
||||||
@Override |
@Override |
||||||
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) |
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) |
||||||
{ |
{ |
||||||
ServerHttpRequest request = exchange.getRequest(); |
ServerHttpRequest request = exchange.getRequest(); |
||||||
// GET DELETE 不过滤
|
// GET DELETE 不过滤
|
||||||
HttpMethod method = request.getMethod(); |
HttpMethod method = request.getMethod(); |
||||||
if (method == null || method == HttpMethod.GET || method == HttpMethod.DELETE) |
if (method == null || method == HttpMethod.GET || method == HttpMethod.DELETE) |
||||||
{ |
{ |
||||||
return chain.filter(exchange); |
return chain.filter(exchange); |
||||||
} |
} |
||||||
// 非json类型,不过滤
|
// 非json类型,不过滤
|
||||||
if (!isJsonRequest(exchange)) |
if (!isJsonRequest(exchange)) |
||||||
{ |
{ |
||||||
return chain.filter(exchange); |
return chain.filter(exchange); |
||||||
} |
} |
||||||
// excludeUrls 不过滤
|
// excludeUrls 不过滤
|
||||||
String url = request.getURI().getPath(); |
String url = request.getURI().getPath(); |
||||||
if (StringUtils.matches(url, xss.getExcludeUrls())) |
if (StringUtils.matches(url, xss.getExcludeUrls())) |
||||||
{ |
{ |
||||||
return chain.filter(exchange); |
return chain.filter(exchange); |
||||||
} |
} |
||||||
ServerHttpRequestDecorator httpRequestDecorator = requestDecorator(exchange); |
ServerHttpRequestDecorator httpRequestDecorator = requestDecorator(exchange); |
||||||
return chain.filter(exchange.mutate().request(httpRequestDecorator).build()); |
return chain.filter(exchange.mutate().request(httpRequestDecorator).build()); |
||||||
|
|
||||||
} |
} |
||||||
|
|
||||||
private ServerHttpRequestDecorator requestDecorator(ServerWebExchange exchange) |
private ServerHttpRequestDecorator requestDecorator(ServerWebExchange exchange) |
||||||
{ |
{ |
||||||
ServerHttpRequestDecorator serverHttpRequestDecorator = new ServerHttpRequestDecorator(exchange.getRequest()) |
ServerHttpRequestDecorator serverHttpRequestDecorator = new ServerHttpRequestDecorator(exchange.getRequest()) |
||||||
{ |
{ |
||||||
@Override |
@Override |
||||||
public Flux<DataBuffer> getBody() |
public Flux<DataBuffer> getBody() |
||||||
{ |
{ |
||||||
Flux<DataBuffer> body = super.getBody(); |
Flux<DataBuffer> body = super.getBody(); |
||||||
return body.buffer().map(dataBuffers -> { |
return body.buffer().map(dataBuffers -> { |
||||||
DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory(); |
DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory(); |
||||||
DataBuffer join = dataBufferFactory.join(dataBuffers); |
DataBuffer join = dataBufferFactory.join(dataBuffers); |
||||||
byte[] content = new byte[join.readableByteCount()]; |
byte[] content = new byte[join.readableByteCount()]; |
||||||
join.read(content); |
join.read(content); |
||||||
DataBufferUtils.release(join); |
DataBufferUtils.release(join); |
||||||
String bodyStr = new String(content, StandardCharsets.UTF_8); |
String bodyStr = new String(content, StandardCharsets.UTF_8); |
||||||
// 防xss攻击过滤
|
// 防xss攻击过滤
|
||||||
bodyStr = EscapeUtil.clean(bodyStr); |
bodyStr = EscapeUtil.clean(bodyStr); |
||||||
// 转成字节
|
// 转成字节
|
||||||
byte[] bytes = bodyStr.getBytes(); |
byte[] bytes = bodyStr.getBytes(); |
||||||
NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT); |
NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT); |
||||||
DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length); |
DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length); |
||||||
buffer.write(bytes); |
buffer.write(bytes); |
||||||
return buffer; |
return buffer; |
||||||
}); |
}); |
||||||
} |
} |
||||||
|
|
||||||
@Override |
@Override |
||||||
public HttpHeaders getHeaders() |
public HttpHeaders getHeaders() |
||||||
{ |
{ |
||||||
HttpHeaders httpHeaders = new HttpHeaders(); |
HttpHeaders httpHeaders = new HttpHeaders(); |
||||||
httpHeaders.putAll(super.getHeaders()); |
httpHeaders.putAll(super.getHeaders()); |
||||||
// 由于修改了请求体的body,导致content-length长度不确定,因此需要删除原先的content-length
|
// 由于修改了请求体的body,导致content-length长度不确定,因此需要删除原先的content-length
|
||||||
httpHeaders.remove(HttpHeaders.CONTENT_LENGTH); |
httpHeaders.remove(HttpHeaders.CONTENT_LENGTH); |
||||||
httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked"); |
httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked"); |
||||||
return httpHeaders; |
return httpHeaders; |
||||||
} |
} |
||||||
|
|
||||||
}; |
}; |
||||||
return serverHttpRequestDecorator; |
return serverHttpRequestDecorator; |
||||||
} |
} |
||||||
|
|
||||||
/** |
/** |
||||||
* 是否是Json请求 |
* 是否是Json请求 |
||||||
* |
* |
||||||
* @param exchange HTTP请求 |
* @param exchange HTTP请求 |
||||||
*/ |
*/ |
||||||
public boolean isJsonRequest(ServerWebExchange exchange) |
public boolean isJsonRequest(ServerWebExchange exchange) |
||||||
{ |
{ |
||||||
String header = exchange.getRequest().getHeaders().getFirst(HttpHeaders.CONTENT_TYPE); |
String header = exchange.getRequest().getHeaders().getFirst(HttpHeaders.CONTENT_TYPE); |
||||||
return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE); |
return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE); |
||||||
} |
} |
||||||
|
|
||||||
@Override |
@Override |
||||||
public int getOrder() |
public int getOrder() |
||||||
{ |
{ |
||||||
return -100; |
return -100; |
||||||
} |
} |
||||||
} |
} |
@ -1,63 +1,63 @@ |
|||||||
package com.ruoyi.gateway.handler; |
package com.yisai.gateway.handler; |
||||||
|
|
||||||
import com.ruoyi.gateway.constant.MessagesConstant; |
import com.yisai.gateway.constant.MessagesConstant; |
||||||
import org.springframework.cloud.gateway.support.NotFoundException; |
import org.springframework.cloud.gateway.support.NotFoundException; |
||||||
import org.slf4j.Logger; |
import org.slf4j.Logger; |
||||||
import org.slf4j.LoggerFactory; |
import org.slf4j.LoggerFactory; |
||||||
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler; |
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler; |
||||||
import org.springframework.context.annotation.Configuration; |
import org.springframework.context.annotation.Configuration; |
||||||
import org.springframework.core.annotation.Order; |
import org.springframework.core.annotation.Order; |
||||||
import org.springframework.http.server.reactive.ServerHttpResponse; |
import org.springframework.http.server.reactive.ServerHttpResponse; |
||||||
import org.springframework.web.server.ResponseStatusException; |
import org.springframework.web.server.ResponseStatusException; |
||||||
import org.springframework.web.server.ServerWebExchange; |
import org.springframework.web.server.ServerWebExchange; |
||||||
import com.ruoyi.common.core.utils.ServletUtils; |
import com.ruoyi.common.core.utils.ServletUtils; |
||||||
import reactor.core.publisher.Mono; |
import reactor.core.publisher.Mono; |
||||||
|
|
||||||
/** |
/** |
||||||
* 网关统一异常处理 |
* 网关统一异常处理 |
||||||
* |
* |
||||||
* @author ruoyi |
* @author ruoyi |
||||||
*/ |
*/ |
||||||
@Order(-1) |
@Order(-1) |
||||||
@Configuration |
@Configuration |
||||||
public class GatewayExceptionHandler implements ErrorWebExceptionHandler |
public class GatewayExceptionHandler implements ErrorWebExceptionHandler |
||||||
{ |
{ |
||||||
private static final Logger log = LoggerFactory.getLogger(GatewayExceptionHandler.class); |
private static final Logger log = LoggerFactory.getLogger(GatewayExceptionHandler.class); |
||||||
|
|
||||||
@Override |
@Override |
||||||
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) |
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) |
||||||
{ |
{ |
||||||
ServerHttpResponse response = exchange.getResponse(); |
ServerHttpResponse response = exchange.getResponse(); |
||||||
|
|
||||||
if (exchange.getResponse().isCommitted()) |
if (exchange.getResponse().isCommitted()) |
||||||
{ |
{ |
||||||
return Mono.error(ex); |
return Mono.error(ex); |
||||||
} |
} |
||||||
|
|
||||||
String msg; |
String msg; |
||||||
|
|
||||||
if (ex instanceof NotFoundException) |
if (ex instanceof NotFoundException) |
||||||
{ |
{ |
||||||
/**服务未找到*/ |
/**服务未找到*/ |
||||||
msg =MessagesConstant.getMessages(exchange,MessagesConstant.MESSAGES_SERVICE_NOT_FOUND_ZH,MessagesConstant.MESSAGES_SERVICE_NOT_FOUND_EN); |
msg =MessagesConstant.getMessages(exchange,MessagesConstant.MESSAGES_SERVICE_NOT_FOUND_ZH,MessagesConstant.MESSAGES_SERVICE_NOT_FOUND_EN); |
||||||
|
|
||||||
} |
} |
||||||
else if (ex instanceof ResponseStatusException) |
else if (ex instanceof ResponseStatusException) |
||||||
{ |
{ |
||||||
ResponseStatusException responseStatusException = (ResponseStatusException) ex; |
ResponseStatusException responseStatusException = (ResponseStatusException) ex; |
||||||
msg = responseStatusException.getMessage(); |
msg = responseStatusException.getMessage(); |
||||||
} |
} |
||||||
else |
else |
||||||
{ |
{ |
||||||
/**内部服务器错误*/ |
/**内部服务器错误*/ |
||||||
//msg="内部服务器错误";
|
//msg="内部服务器错误";
|
||||||
msg =MessagesConstant.getMessages(exchange,MessagesConstant.MESSAGES_INTERNAL_SERVER_ERROR_ZH,MessagesConstant.MESSAGES_INTERNAL_SERVER_ERROR_EN); |
msg =MessagesConstant.getMessages(exchange,MessagesConstant.MESSAGES_INTERNAL_SERVER_ERROR_ZH,MessagesConstant.MESSAGES_INTERNAL_SERVER_ERROR_EN); |
||||||
} |
} |
||||||
|
|
||||||
log.error("[网关异常处理]请求路径:{},异常信息:{}", exchange.getRequest().getPath(), ex.getMessage()); |
log.error("[网关异常处理]请求路径:{},异常信息:{}", exchange.getRequest().getPath(), ex.getMessage()); |
||||||
|
|
||||||
return ServletUtils.webFluxResponseWriter(response, msg); |
return ServletUtils.webFluxResponseWriter(response, msg); |
||||||
} |
} |
||||||
|
|
||||||
|
|
||||||
} |
} |
@ -1,41 +1,41 @@ |
|||||||
package com.ruoyi.gateway.handler; |
package com.yisai.gateway.handler; |
||||||
|
|
||||||
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager; |
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager; |
||||||
import com.alibaba.csp.sentinel.slots.block.BlockException; |
import com.alibaba.csp.sentinel.slots.block.BlockException; |
||||||
import com.ruoyi.common.core.utils.ServletUtils; |
import com.ruoyi.common.core.utils.ServletUtils; |
||||||
import org.springframework.web.reactive.function.server.ServerResponse; |
import org.springframework.web.reactive.function.server.ServerResponse; |
||||||
import org.springframework.web.server.ServerWebExchange; |
import org.springframework.web.server.ServerWebExchange; |
||||||
import org.springframework.web.server.WebExceptionHandler; |
import org.springframework.web.server.WebExceptionHandler; |
||||||
import reactor.core.publisher.Mono; |
import reactor.core.publisher.Mono; |
||||||
|
|
||||||
/** |
/** |
||||||
* 自定义限流异常处理 |
* 自定义限流异常处理 |
||||||
* |
* |
||||||
* @author ruoyi |
* @author ruoyi |
||||||
*/ |
*/ |
||||||
public class SentinelFallbackHandler implements WebExceptionHandler |
public class SentinelFallbackHandler implements WebExceptionHandler |
||||||
{ |
{ |
||||||
private Mono<Void> writeResponse(ServerResponse response, ServerWebExchange exchange) |
private Mono<Void> writeResponse(ServerResponse response, ServerWebExchange exchange) |
||||||
{ |
{ |
||||||
return ServletUtils.webFluxResponseWriter(exchange.getResponse(), "请求超过最大数,请稍候再试"); |
return ServletUtils.webFluxResponseWriter(exchange.getResponse(), "请求超过最大数,请稍候再试"); |
||||||
} |
} |
||||||
|
|
||||||
@Override |
@Override |
||||||
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) |
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) |
||||||
{ |
{ |
||||||
if (exchange.getResponse().isCommitted()) |
if (exchange.getResponse().isCommitted()) |
||||||
{ |
{ |
||||||
return Mono.error(ex); |
return Mono.error(ex); |
||||||
} |
} |
||||||
if (!BlockException.isBlockException(ex)) |
if (!BlockException.isBlockException(ex)) |
||||||
{ |
{ |
||||||
return Mono.error(ex); |
return Mono.error(ex); |
||||||
} |
} |
||||||
return handleBlockedRequest(exchange, ex).flatMap(response -> writeResponse(response, exchange)); |
return handleBlockedRequest(exchange, ex).flatMap(response -> writeResponse(response, exchange)); |
||||||
} |
} |
||||||
|
|
||||||
private Mono<ServerResponse> handleBlockedRequest(ServerWebExchange exchange, Throwable throwable) |
private Mono<ServerResponse> handleBlockedRequest(ServerWebExchange exchange, Throwable throwable) |
||||||
{ |
{ |
||||||
return GatewayCallbackManager.getBlockHandler().handleRequest(exchange, throwable); |
return GatewayCallbackManager.getBlockHandler().handleRequest(exchange, throwable); |
||||||
} |
} |
||||||
} |
} |
@ -1,56 +1,56 @@ |
|||||||
package com.ruoyi.gateway.handler; |
package com.yisai.gateway.handler; |
||||||
|
|
||||||
import java.util.Optional; |
import java.util.Optional; |
||||||
import org.springframework.beans.factory.annotation.Autowired; |
import org.springframework.beans.factory.annotation.Autowired; |
||||||
import org.springframework.http.HttpStatus; |
import org.springframework.http.HttpStatus; |
||||||
import org.springframework.http.ResponseEntity; |
import org.springframework.http.ResponseEntity; |
||||||
import org.springframework.web.bind.annotation.GetMapping; |
import org.springframework.web.bind.annotation.GetMapping; |
||||||
import org.springframework.web.bind.annotation.RequestMapping; |
import org.springframework.web.bind.annotation.RequestMapping; |
||||||
import org.springframework.web.bind.annotation.RestController; |
import org.springframework.web.bind.annotation.RestController; |
||||||
import reactor.core.publisher.Mono; |
import reactor.core.publisher.Mono; |
||||||
import springfox.documentation.swagger.web.SecurityConfiguration; |
import springfox.documentation.swagger.web.SecurityConfiguration; |
||||||
import springfox.documentation.swagger.web.SecurityConfigurationBuilder; |
import springfox.documentation.swagger.web.SecurityConfigurationBuilder; |
||||||
import springfox.documentation.swagger.web.SwaggerResourcesProvider; |
import springfox.documentation.swagger.web.SwaggerResourcesProvider; |
||||||
import springfox.documentation.swagger.web.UiConfiguration; |
import springfox.documentation.swagger.web.UiConfiguration; |
||||||
import springfox.documentation.swagger.web.UiConfigurationBuilder; |
import springfox.documentation.swagger.web.UiConfigurationBuilder; |
||||||
|
|
||||||
@RestController |
@RestController |
||||||
@RequestMapping("/swagger-resources") |
@RequestMapping("/swagger-resources") |
||||||
public class SwaggerHandler |
public class SwaggerHandler |
||||||
{ |
{ |
||||||
@Autowired(required = false) |
@Autowired(required = false) |
||||||
private SecurityConfiguration securityConfiguration; |
private SecurityConfiguration securityConfiguration; |
||||||
|
|
||||||
@Autowired(required = false) |
@Autowired(required = false) |
||||||
private UiConfiguration uiConfiguration; |
private UiConfiguration uiConfiguration; |
||||||
|
|
||||||
private final SwaggerResourcesProvider swaggerResources; |
private final SwaggerResourcesProvider swaggerResources; |
||||||
|
|
||||||
@Autowired |
@Autowired |
||||||
public SwaggerHandler(SwaggerResourcesProvider swaggerResources) |
public SwaggerHandler(SwaggerResourcesProvider swaggerResources) |
||||||
{ |
{ |
||||||
this.swaggerResources = swaggerResources; |
this.swaggerResources = swaggerResources; |
||||||
} |
} |
||||||
|
|
||||||
@GetMapping("/configuration/security") |
@GetMapping("/configuration/security") |
||||||
public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() |
public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() |
||||||
{ |
{ |
||||||
return Mono.just(new ResponseEntity<>( |
return Mono.just(new ResponseEntity<>( |
||||||
Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()), |
Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()), |
||||||
HttpStatus.OK)); |
HttpStatus.OK)); |
||||||
} |
} |
||||||
|
|
||||||
@GetMapping("/configuration/ui") |
@GetMapping("/configuration/ui") |
||||||
public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() |
public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() |
||||||
{ |
{ |
||||||
return Mono.just(new ResponseEntity<>( |
return Mono.just(new ResponseEntity<>( |
||||||
Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK)); |
Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK)); |
||||||
} |
} |
||||||
|
|
||||||
@SuppressWarnings("rawtypes") |
@SuppressWarnings("rawtypes") |
||||||
@GetMapping("") |
@GetMapping("") |
||||||
public Mono<ResponseEntity> swaggerResources() |
public Mono<ResponseEntity> swaggerResources() |
||||||
{ |
{ |
||||||
return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK))); |
return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK))); |
||||||
} |
} |
||||||
} |
} |
@ -1,41 +1,41 @@ |
|||||||
package com.ruoyi.gateway.handler; |
package com.yisai.gateway.handler; |
||||||
|
|
||||||
import java.io.IOException; |
import java.io.IOException; |
||||||
import org.springframework.beans.factory.annotation.Autowired; |
import org.springframework.beans.factory.annotation.Autowired; |
||||||
import org.springframework.http.HttpStatus; |
import org.springframework.http.HttpStatus; |
||||||
import org.springframework.stereotype.Component; |
import org.springframework.stereotype.Component; |
||||||
import org.springframework.web.reactive.function.BodyInserters; |
import org.springframework.web.reactive.function.BodyInserters; |
||||||
import org.springframework.web.reactive.function.server.HandlerFunction; |
import org.springframework.web.reactive.function.server.HandlerFunction; |
||||||
import org.springframework.web.reactive.function.server.ServerRequest; |
import org.springframework.web.reactive.function.server.ServerRequest; |
||||||
import org.springframework.web.reactive.function.server.ServerResponse; |
import org.springframework.web.reactive.function.server.ServerResponse; |
||||||
import com.ruoyi.common.core.exception.CaptchaException; |
import com.ruoyi.common.core.exception.CaptchaException; |
||||||
import com.ruoyi.common.core.web.domain.AjaxResult; |
import com.ruoyi.common.core.web.domain.AjaxResult; |
||||||
import com.ruoyi.gateway.service.ValidateCodeService; |
import com.yisai.gateway.service.ValidateCodeService; |
||||||
import reactor.core.publisher.Mono; |
import reactor.core.publisher.Mono; |
||||||
|
|
||||||
/** |
/** |
||||||
* 验证码获取 |
* 验证码获取 |
||||||
* |
* |
||||||
* @author ruoyi |
* @author ruoyi |
||||||
*/ |
*/ |
||||||
@Component |
@Component |
||||||
public class ValidateCodeHandler implements HandlerFunction<ServerResponse> |
public class ValidateCodeHandler implements HandlerFunction<ServerResponse> |
||||||
{ |
{ |
||||||
@Autowired |
@Autowired |
||||||
private ValidateCodeService validateCodeService; |
private ValidateCodeService validateCodeService; |
||||||
|
|
||||||
@Override |
@Override |
||||||
public Mono<ServerResponse> handle(ServerRequest serverRequest) |
public Mono<ServerResponse> handle(ServerRequest serverRequest) |
||||||
{ |
{ |
||||||
AjaxResult ajax; |
AjaxResult ajax; |
||||||
try |
try |
||||||
{ |
{ |
||||||
ajax = validateCodeService.createCaptcha(); |
ajax = validateCodeService.createCaptcha(); |
||||||
} |
} |
||||||
catch (CaptchaException | IOException e) |
catch (CaptchaException | IOException e) |
||||||
{ |
{ |
||||||
return Mono.error(e); |
return Mono.error(e); |
||||||
} |
} |
||||||
return ServerResponse.status(HttpStatus.OK).body(BodyInserters.fromValue(ajax)); |
return ServerResponse.status(HttpStatus.OK).body(BodyInserters.fromValue(ajax)); |
||||||
} |
} |
||||||
} |
} |
@ -1,23 +1,23 @@ |
|||||||
package com.ruoyi.gateway.service; |
package com.yisai.gateway.service; |
||||||
|
|
||||||
import java.io.IOException; |
import java.io.IOException; |
||||||
import com.ruoyi.common.core.exception.CaptchaException; |
import com.ruoyi.common.core.exception.CaptchaException; |
||||||
import com.ruoyi.common.core.web.domain.AjaxResult; |
import com.ruoyi.common.core.web.domain.AjaxResult; |
||||||
|
|
||||||
/** |
/** |
||||||
* 验证码处理 |
* 验证码处理 |
||||||
* |
* |
||||||
* @author ruoyi |
* @author ruoyi |
||||||
*/ |
*/ |
||||||
public interface ValidateCodeService |
public interface ValidateCodeService |
||||||
{ |
{ |
||||||
/** |
/** |
||||||
* 生成验证码 |
* 生成验证码 |
||||||
*/ |
*/ |
||||||
public AjaxResult createCaptcha() throws IOException, CaptchaException; |
public AjaxResult createCaptcha() throws IOException, CaptchaException; |
||||||
|
|
||||||
/** |
/** |
||||||
* 校验验证码 |
* 校验验证码 |
||||||
*/ |
*/ |
||||||
public void checkCaptcha(String key, String value) throws CaptchaException; |
public void checkCaptcha(String key, String value) throws CaptchaException; |
||||||
} |
} |
@ -1,118 +1,118 @@ |
|||||||
package com.ruoyi.gateway.service.impl; |
package com.yisai.gateway.service.impl; |
||||||
|
|
||||||
import java.awt.image.BufferedImage; |
import java.awt.image.BufferedImage; |
||||||
import java.io.IOException; |
import java.io.IOException; |
||||||
import java.util.concurrent.TimeUnit; |
import java.util.concurrent.TimeUnit; |
||||||
import javax.annotation.Resource; |
import javax.annotation.Resource; |
||||||
import javax.imageio.ImageIO; |
import javax.imageio.ImageIO; |
||||||
import org.springframework.beans.factory.annotation.Autowired; |
import org.springframework.beans.factory.annotation.Autowired; |
||||||
import org.springframework.stereotype.Service; |
import org.springframework.stereotype.Service; |
||||||
import org.springframework.util.FastByteArrayOutputStream; |
import org.springframework.util.FastByteArrayOutputStream; |
||||||
import com.google.code.kaptcha.Producer; |
import com.google.code.kaptcha.Producer; |
||||||
import com.ruoyi.common.core.constant.Constants; |
import com.ruoyi.common.core.constant.Constants; |
||||||
import com.ruoyi.common.core.exception.CaptchaException; |
import com.ruoyi.common.core.exception.CaptchaException; |
||||||
import com.ruoyi.common.core.utils.StringUtils; |
import com.ruoyi.common.core.utils.StringUtils; |
||||||
import com.ruoyi.common.core.utils.sign.Base64; |
import com.ruoyi.common.core.utils.sign.Base64; |
||||||
import com.ruoyi.common.core.utils.uuid.IdUtils; |
import com.ruoyi.common.core.utils.uuid.IdUtils; |
||||||
import com.ruoyi.common.core.web.domain.AjaxResult; |
import com.ruoyi.common.core.web.domain.AjaxResult; |
||||||
import com.ruoyi.common.redis.service.RedisService; |
import com.ruoyi.common.redis.service.RedisService; |
||||||
import com.ruoyi.gateway.config.properties.CaptchaProperties; |
import com.yisai.gateway.config.properties.CaptchaProperties; |
||||||
import com.ruoyi.gateway.service.ValidateCodeService; |
import com.yisai.gateway.service.ValidateCodeService; |
||||||
|
|
||||||
/** |
/** |
||||||
* 验证码实现处理 |
* 验证码实现处理 |
||||||
* |
* |
||||||
* @author ruoyi |
* @author ruoyi |
||||||
*/ |
*/ |
||||||
@Service |
@Service |
||||||
public class ValidateCodeServiceImpl implements ValidateCodeService |
public class ValidateCodeServiceImpl implements ValidateCodeService |
||||||
{ |
{ |
||||||
@Resource(name = "captchaProducer") |
@Resource(name = "captchaProducer") |
||||||
private Producer captchaProducer; |
private Producer captchaProducer; |
||||||
|
|
||||||
@Resource(name = "captchaProducerMath") |
@Resource(name = "captchaProducerMath") |
||||||
private Producer captchaProducerMath; |
private Producer captchaProducerMath; |
||||||
|
|
||||||
@Autowired |
@Autowired |
||||||
private RedisService redisService; |
private RedisService redisService; |
||||||
|
|
||||||
@Autowired |
@Autowired |
||||||
private CaptchaProperties captchaProperties; |
private CaptchaProperties captchaProperties; |
||||||
|
|
||||||
/** |
/** |
||||||
* 生成验证码 |
* 生成验证码 |
||||||
*/ |
*/ |
||||||
@Override |
@Override |
||||||
public AjaxResult createCaptcha() throws IOException, CaptchaException |
public AjaxResult createCaptcha() throws IOException, CaptchaException |
||||||
{ |
{ |
||||||
AjaxResult ajax = AjaxResult.success(); |
AjaxResult ajax = AjaxResult.success(); |
||||||
boolean captchaOnOff = captchaProperties.getEnabled(); |
boolean captchaOnOff = captchaProperties.getEnabled(); |
||||||
ajax.put("captchaOnOff", captchaOnOff); |
ajax.put("captchaOnOff", captchaOnOff); |
||||||
if (!captchaOnOff) |
if (!captchaOnOff) |
||||||
{ |
{ |
||||||
return ajax; |
return ajax; |
||||||
} |
} |
||||||
|
|
||||||
// 保存验证码信息
|
// 保存验证码信息
|
||||||
String uuid = IdUtils.simpleUUID(); |
String uuid = IdUtils.simpleUUID(); |
||||||
String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid; |
String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid; |
||||||
|
|
||||||
String capStr = null, code = null; |
String capStr = null, code = null; |
||||||
BufferedImage image = null; |
BufferedImage image = null; |
||||||
|
|
||||||
String captchaType = captchaProperties.getType(); |
String captchaType = captchaProperties.getType(); |
||||||
// 生成验证码
|
// 生成验证码
|
||||||
if ("math".equals(captchaType)) |
if ("math".equals(captchaType)) |
||||||
{ |
{ |
||||||
String capText = captchaProducerMath.createText(); |
String capText = captchaProducerMath.createText(); |
||||||
capStr = capText.substring(0, capText.lastIndexOf("@")); |
capStr = capText.substring(0, capText.lastIndexOf("@")); |
||||||
code = capText.substring(capText.lastIndexOf("@") + 1); |
code = capText.substring(capText.lastIndexOf("@") + 1); |
||||||
image = captchaProducerMath.createImage(capStr); |
image = captchaProducerMath.createImage(capStr); |
||||||
} |
} |
||||||
else if ("char".equals(captchaType)) |
else if ("char".equals(captchaType)) |
||||||
{ |
{ |
||||||
capStr = code = captchaProducer.createText(); |
capStr = code = captchaProducer.createText(); |
||||||
image = captchaProducer.createImage(capStr); |
image = captchaProducer.createImage(capStr); |
||||||
} |
} |
||||||
|
|
||||||
redisService.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES); |
redisService.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES); |
||||||
// 转换流信息写出
|
// 转换流信息写出
|
||||||
FastByteArrayOutputStream os = new FastByteArrayOutputStream(); |
FastByteArrayOutputStream os = new FastByteArrayOutputStream(); |
||||||
try |
try |
||||||
{ |
{ |
||||||
ImageIO.write(image, "jpg", os); |
ImageIO.write(image, "jpg", os); |
||||||
} |
} |
||||||
catch (IOException e) |
catch (IOException e) |
||||||
{ |
{ |
||||||
return AjaxResult.error(e.getMessage()); |
return AjaxResult.error(e.getMessage()); |
||||||
} |
} |
||||||
|
|
||||||
ajax.put("uuid", uuid); |
ajax.put("uuid", uuid); |
||||||
ajax.put("img", Base64.encode(os.toByteArray())); |
ajax.put("img", Base64.encode(os.toByteArray())); |
||||||
return ajax; |
return ajax; |
||||||
} |
} |
||||||
|
|
||||||
/** |
/** |
||||||
* 校验验证码 |
* 校验验证码 |
||||||
*/ |
*/ |
||||||
@Override |
@Override |
||||||
public void checkCaptcha(String code, String uuid) throws CaptchaException |
public void checkCaptcha(String code, String uuid) throws CaptchaException |
||||||
{ |
{ |
||||||
if (StringUtils.isEmpty(code)) |
if (StringUtils.isEmpty(code)) |
||||||
{ |
{ |
||||||
throw new CaptchaException("验证码不能为空"); |
throw new CaptchaException("验证码不能为空"); |
||||||
} |
} |
||||||
if (StringUtils.isEmpty(uuid)) |
if (StringUtils.isEmpty(uuid)) |
||||||
{ |
{ |
||||||
throw new CaptchaException("验证码已失效"); |
throw new CaptchaException("验证码已失效"); |
||||||
} |
} |
||||||
String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid; |
String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid; |
||||||
String captcha = redisService.getCacheObject(verifyKey); |
String captcha = redisService.getCacheObject(verifyKey); |
||||||
redisService.deleteObject(verifyKey); |
redisService.deleteObject(verifyKey); |
||||||
|
|
||||||
if (!code.equalsIgnoreCase(captcha)) |
if (!code.equalsIgnoreCase(captcha)) |
||||||
{ |
{ |
||||||
throw new CaptchaException("验证码错误"); |
throw new CaptchaException("验证码错误"); |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
Loading…
Reference in new issue