全局过滤器(默认对所有路由生效)
全局过滤器(认证)
/**
* @描述: TODO 全局认证过滤器,不需要在配置文件中配置,作用于所有的请求
* @作者: lixing
* @日期 2021/6/17 9:06
*/
@Component
public class MyAuthorizeGlobalFilter implements GlobalFilter, Ordered {
/** 读取配置文件中的数据 */
@Resource
private CustomProperties customProperties;
/** redis持久化工具类 */
@Resource
private RedissonSingleService<String> redissonSingleServiceString;
/**
* 过滤器执行的顺序,值越小,执行顺序越靠前
*/
@Override
public int getOrder() {
return GatewayFilterOrderEnum.MY_AUTHORIZE.getValue();
}
/**
* TODO 全局"前置"过滤器逻辑
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest serverHttpRequest = exchange.getRequest();
ServerHttpResponse serverHttpResponse = exchange.getResponse();
// 原始请求地址: 127.0.0.1:8800/springCloudGateway/auth/login/doLogin
// 转化后的地址: /bffAuth/login/doLogin
String reqPath = serverHttpRequest.getURI().getPath();
// 全局白名单地址,例如:注册、登陆、忘记密码发送短信等等
List<String> whiteUrlList = customProperties.getSys().getWhiteUrlList();
/*
* 请求白名单过滤
*/
// /login/** 匹配 /login 开头
// /trip/api/*x 匹配 /trip/api/x,/trip/api/ax,/trip/api/abx ;但不匹配 /trip/abc/x
// /trip/a/a?x 匹配 /trip/a/abx;但不匹配 /trip/a/ax,/trip/a/abcx
// /**/api/alie 匹配 /trip/api/alie,/trip/dax/api/alie;但不匹配 /trip/a/api
// /**/*.htmlm 匹配所有以.htmlm结尾的路径
PathMatcher pathMatcher = new AntPathMatcher();
for (String authIgnoreTemp : whiteUrlList) {
if (StrUtil.isEffective(authIgnoreTemp) && pathMatcher.match(authIgnoreTemp, reqPath)) {
LoggerUtil.info(MessageFormat.format("MyAuthorizeGlobalFilter 全局认证过滤器 ---- 地址无需登陆:{0}",reqPath));
return chain.filter(exchange);
}
}
LoggerUtil.info(MessageFormat.format("MyAuthorizeGlobalFilter 全局认证过滤器 ---- 地址需要登陆:{0}",reqPath));
LoggerUtil.info("");
/*
* 对请求进行拦截并校验TOKEN
*/
String token = serverHttpRequest.getHeaders().getFirst(SysKeyEnum.TOKEN.getKey());
// 非空校验
if (!StrUtil.isEffective(token)) {
// 拦截,提示未授权错误,401
//serverHttpResponse.setStatusCode(HttpStatus.UNAUTHORIZED);
// 拦截结束请求
//return serverHttpResponse.setComplete();
return MonoResponseUtil.getVoidMono(serverHttpResponse, new BaseResult<String>().fail("TOKEN缺失"));
}
// 校验token,获取用户的登录对象
try {
BaseLoginUserInfo baseLoginUserInfo = JwtUtil.verifyJwtForHs256(token);
// redis中校验登录状态
String versionKey = MessageFormat.format(SysKeyEnum.LOGIN_USER_VERSION.getKey(), SysKeyConstant.PROJECTNAME, baseLoginUserInfo.getUserAccount());
if (!redissonSingleServiceString.isExists(versionKey)) {
// redis中没有当前key,则表示登录超时了,需要重写登录
return MonoResponseUtil.getVoidMono(serverHttpResponse, new BaseResult<String>().fail(SysStateEnum.RESPONSE_STATUS_FALSE_TOKEN_TIMEOUT.getDescribe()));
} else {
// 判断当前的version和redis中的version是否一致,不一致则表示当前已经有人登录,需要重新登录
String tokenVersion = redissonSingleServiceString.getKey(versionKey);
if (!baseLoginUserInfo.getVersion().equals(tokenVersion)) {
return MonoResponseUtil.getVoidMono(serverHttpResponse, new BaseResult<String>().fail(SysStateEnum.RESPONSE_STATUS_FALSE_TOKEN_EXISTS.getDescribe()));
}
}
// 修改请求求
Consumer<HttpHeaders> httpHeaders = httpHeader -> {
httpHeader.set(SysKeyEnum.USERINFO_ACCOUNT.getKey(), baseLoginUserInfo.getUserAccount());
httpHeader.set(SysKeyEnum.USERINFO_PHONE.getKey(), baseLoginUserInfo.getUserAccount());
httpHeader.remove(SysKeyEnum.TOKEN.getKey());
};
// 从原始交换对象获得一个新的 ServerHttpRequest 实例
ServerHttpRequest serverHttpRequestMutable = serverHttpRequest.mutate().headers(httpHeaders).build();
// 从原始交换对象获得一个新的 ServerWebExchange 实例
ServerWebExchange serverWebExchangeMutable = exchange.mutate().request(serverHttpRequestMutable).build();
//
return chain.filter(serverWebExchangeMutable).then(Mono.fromRunnable(() -> {
// TODO 全局"后置"过滤器逻辑
LoggerUtil.info(MessageFormat.format("MyAuthorizeGlobalFilter 全局认证过滤器 ---- 全局后置过滤器回调逻辑:{0}",reqPath));
}));
} catch (Exception e) {
return MonoResponseUtil.getVoidMono(serverHttpResponse, new BaseResult<String>().fail(e.getMessage()));
}
}
}
网关过滤器(局部过滤器,需要为相关路由配置才可生效)
IP网关过滤器
1、创建IP网关过滤器
/**
* @描述: TODO IP网关过滤器,需要为相关路由配置上才可生效
* @作者: lixing
* @日期 2021/6/24 10:25
*/
public class MyIpGatewayFilter implements GatewayFilter, Ordered {
private CustomProperties customProperties;
private MyIpGatewayFilterFactoryConfig myIpGatewayFilterFactoryConfig;
MyIpGatewayFilter(CustomProperties customProperties, MyIpGatewayFilterFactoryConfig myIpGatewayFilterFactoryConfig) {
this.customProperties = customProperties;
this.myIpGatewayFilterFactoryConfig = myIpGatewayFilterFactoryConfig;
}
/** 过滤器执行的顺序,值越小,执行顺序越靠前 */
@Override
public int getOrder() {
return GatewayFilterOrderEnum.MY_IP.getValue();
}
/** 过滤 */
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
if ("*".equalsIgnoreCase(myIpGatewayFilterFactoryConfig.getWhiteIp())) {
// 对所有ip放行
return chain.filter(exchange);
} else {
ServerHttpRequest serverHttpRequest = exchange.getRequest();
ServerHttpResponse serverHttpResponse = exchange.getResponse();
// 请求地址
String reqPath = serverHttpRequest.getURI().getPath();
// 当前请求的ip
String reqIp = Objects.requireNonNull(exchange.getRequest().getRemoteAddress()).getAddress().getHostAddress();
// 公共白名单列表
List<String> whiteIpList = customProperties.getSys().getWhiteIpList();
// 局部白名单列表
List<String> configIpList = Arrays.asList(myIpGatewayFilterFactoryConfig.getWhiteIp().split(","));
//
if (whiteIpList.contains(reqIp) || configIpList.contains(reqIp)) {
LoggerUtil.info(MessageFormat.format("MyIpGatewayFilter IP网关过滤器 ---- IP无需拦截:{0}", reqIp));
LoggerUtil.info("");
return chain.filter(exchange);
}
return MonoResponseUtil.getVoidMono(serverHttpResponse, new BaseResult<String>().fail("您还没有权限访问,请联系管理员"));
}
}
}
2、创建过滤器参数配置类
/**
* @描述: TODO IP网关过滤器参数配置类
* @作者: lixing
* @日期 2021/6/25 9:22
*/
@Data
@NoArgsConstructor
public class MyIpGatewayFilterFactoryConfig {
/** 默认白名单ip列表,*:表示对所有ip放行,指定ip列表的格式为:127.0.0.1,192.168.1.110 */
private String whiteIp;
}
3、创建过滤器工厂
/**
* @描述: TODO IP网关过滤器工厂,需要为相关路由配置上才可生效
* @作者: lixing
* @日期 2021/6/24 10:25
*/
@Component
public class MyIpGatewayFilterFactory extends AbstractGatewayFilterFactory<MyIpGatewayFilterFactoryConfig> {
@Resource
private CustomProperties customProperties;
public MyIpGatewayFilterFactory() {
super(MyIpGatewayFilterFactoryConfig.class);
}
/** 自定义配置类-内部类,用于传入配置参数 */
@Override
public List<String> shortcutFieldOrder() {
return Collections.singletonList("whiteIp");
}
/**
* 过滤器逻辑
*/
@Override
public GatewayFilter apply(MyIpGatewayFilterFactoryConfig config) {
return new MyIpGatewayFilter(customProperties, config);
}
}
4、配置IP网关过滤器
# TODO 基于 【BFF-AUTH】 服务的路由配置
- id: BFF-AUTH-ROUTE
uri: lb://bffAuth
predicates:
- Path=/springCloudGateway/auth/**
filters:
# 自定义 [MyIpGatewayFilter] 网关过滤器。*表示允许所有ip请求,其它格式为:127.0.0.1,192.168.0.110
- MyIp=127.0.0.1,192.168.1.1
请求参数网关过滤器
1、 创建请求参数网关过滤器
/**
* @描述: TODO 请求参数网关过滤器,需要为相关路由配置上才可生效
* @作者: lixing
* @日期 2021/6/24 10:25
*/
public class MyRequestParamsGatewayFilter implements GatewayFilter, Ordered {
/** 通过构造函数初始化参数配置类 */
private MyRequestParamsGatewayFilterFactoryConfig myRequestParamsGatewayFilterFactoryConfig;
public MyRequestParamsGatewayFilter(MyRequestParamsGatewayFilterFactoryConfig myRequestParamsGatewayFilterFactoryConfig) {
this.myRequestParamsGatewayFilterFactoryConfig = myRequestParamsGatewayFilterFactoryConfig;
}
/** 过滤器执行的顺序,值越小,执行顺序越靠前 */
@Override
public int getOrder() {
return GatewayFilterOrderEnum.MY_REQUEST_PARAMS.getValue();
}
/**
* TODO 网关“前置”过滤器逻辑
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
//
String schema = request.getURI().getScheme();
if ((!"http".equalsIgnoreCase(schema) && !"https".equalsIgnoreCase(schema))) {
return chain.filter(exchange);
}
// 请求地址
String reqPath = request.getPath().toString();
// 请求方式:POST
String method = request.getMethodValue();
// 媒体类型:浏览器以JSON形式对资源进行解析
MediaType mediaType = exchange.getRequest().getHeaders().getContentType();
// 请求中的参数是否需要解密
exchange.getAttributes().put("isDecrypt", myRequestParamsGatewayFilterFactoryConfig.getIsDecrypt());
if (SysKeyEnum.GET.getKey().equalsIgnoreCase(method)) {
/*
* GET 请求
*/
MultiValueMap<String, String> queryParams = request.getQueryParams();
if (SysStateEnum.STATE_YES.getDescribe().equalsIgnoreCase(myRequestParamsGatewayFilterFactoryConfig.getIsDecrypt())) {
LoggerUtil.info("解密成功");
}
return chain.filter(exchange)
// TODO 网关“后置”过滤器逻辑
.then(Mono.fromRunnable(() -> {
if (SysStateEnum.STATE_YES.getDescribe().equalsIgnoreCase(myRequestParamsGatewayFilterFactoryConfig.getIsPrint())) {
LoggerUtil.info("");
LoggerUtil.info(MessageFormat.format("MyRequestParamsGatewayFilter 入参全局过滤器 ---- start [GET]:{0}", reqPath));
if (SysStateEnum.STATE_YES.getDescribe().equalsIgnoreCase(myRequestParamsGatewayFilterFactoryConfig.getIsDecrypt())) {
LoggerUtil.info(MessageFormat.format("入参解密前: {0}", JSONObject.toJSONString(queryParams)));
LoggerUtil.info(MessageFormat.format("入参解密后: {0}", JSONObject.toJSONString(queryParams)));
} else {
LoggerUtil.info(MessageFormat.format("入参: {0}", JSONObject.toJSONString(queryParams)));
}
LoggerUtil.info("MyRequestParamsGatewayFilter 入参全局过滤器 ---- end");
}
}));
} else if (SysKeyEnum.POST.getKey().equalsIgnoreCase(method) && MediaType.APPLICATION_JSON.isCompatibleWith(mediaType)) {
ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders());
// ServerRequest serverRequest = new DefaultServerRequest(exchange);
// 读取 body 中的内容并修改
AtomicReference<JSONObject> bodyJsonObj = new AtomicReference<>(new JSONObject());
Mono<String> modifiedBody = serverRequest.bodyToMono(String.class).flatMap(body -> {
bodyJsonObj.set(JSON.parseObject(body));
if (SysStateEnum.STATE_YES.getDescribe().equalsIgnoreCase(myRequestParamsGatewayFilterFactoryConfig.getIsDecrypt())) {
LoggerUtil.info("解密成功");
}
return Mono.just(JSONObject.toJSONString(bodyJsonObj));
});
/*
* TODO 下面的将请求体再次封装写回到request里,传到下一级,否则,由于请求体已被消费,后续的服务将取不到值
* CacheBodyGlobalFilter这个全局过滤器的目的就是把原有的request请求中的body内容读出来,并且使用ServerHttpRequestDecorator这个请求装饰器对request进行包装,重写getBody方法,并把包装后的请求放到过滤器链中传递下去。
* 这样后面的过滤器中再使用exchange.getRequest().getBody()来获取body时,实际上就是调用的重载后的getBody方法,获取的最先已经缓存了的body数据
*/
BodyInserter<Mono<String>, ReactiveHttpOutputMessage> bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class);
HttpHeaders headers = new HttpHeaders();
headers.putAll(exchange.getRequest().getHeaders());
// the new content type will be computed by bodyInserter and then set in the request decorator
headers.remove(HttpHeaders.CONTENT_LENGTH);
CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, headers);
return bodyInserter.insert(outputMessage, new BodyInserterContext()).then(Mono.defer(() -> {
ServerHttpRequestDecorator serverHttpRequestDecorator = new ServerHttpRequestDecorator(exchange.getRequest()) {
@Override
public HttpHeaders getHeaders() {
long contentLength = headers.getContentLength();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.putAll(super.getHeaders());
if (contentLength > 0) {
httpHeaders.setContentLength(contentLength);
} else {
httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
}
return httpHeaders;
}
@Override
public Flux<DataBuffer> getBody() {
Flux<DataBuffer> dataBufferFlux = outputMessage.getBody();
return dataBufferFlux;
}
};
// 从原始交换对象获得一个新的 ServerWebExchange 实例
ServerWebExchange serverWebExchangeMutable = exchange.mutate().request(serverHttpRequestDecorator).build();
return chain.filter(serverWebExchangeMutable)
// TODO 网关“后置”过滤器逻辑
.then(Mono.fromRunnable(() -> {
if (SysStateEnum.STATE_YES.getDescribe().equalsIgnoreCase(myRequestParamsGatewayFilterFactoryConfig.getIsPrint())) {
LoggerUtil.info("");
LoggerUtil.info(MessageFormat.format("MyRequestParamsGatewayFilter ---- start [POST]:{0}", reqPath));
if (SysStateEnum.STATE_YES.getDescribe().equalsIgnoreCase(myRequestParamsGatewayFilterFactoryConfig.getIsDecrypt())) {
LoggerUtil.info(MessageFormat.format("请求入参解密前: {0}", bodyJsonObj.get().toJSONString()));
LoggerUtil.info(MessageFormat.format("请求入参解密后: {0}", bodyJsonObj.get().toJSONString()));
} else {
LoggerUtil.info(MessageFormat.format("请求入参: {0}", bodyJsonObj.get().toJSONString()));
}
LoggerUtil.info("MyRequestParamsGatewayFilter ---- end");
LoggerUtil.info("");
}
}));
}));
} else {
return chain.filter(exchange);
}
}
}
2、创建过滤器参数配置类
/**
* @描述: 请求参数网关过滤器配置类
* @作者: lixing
* @日期 2021/6/25 9:22
*/
@Data
@NoArgsConstructor
public class MyRequestParamsGatewayFilterFactoryConfig {
/** 是否打印请求参数 */
private String isPrint;
/** 是否解密请求参数 */
private String isDecrypt;
}
3、创建过滤器工厂
/**
* @描述: TODO 请求参数网关过滤器工厂,需要为相关路由配置上才可生效
* @作者: lixing
* @日期 2021/6/24 10:25
*/
@Component
public class MyRequestParamsGatewayFilterFactory extends AbstractGatewayFilterFactory<MyRequestParamsGatewayFilterFactoryConfig> {
/*
* 构造函数
*/
public MyRequestParamsGatewayFilterFactory() {
super(MyRequestParamsGatewayFilterFactoryConfig.class);
}
/*
* 自定义配置类-内部类,用于传入配置参数
*/
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("isPrint","isDecrypt");
}
/*
* 过滤器逻辑
*/
@Override
public GatewayFilter apply(MyRequestParamsGatewayFilterFactoryConfig config) {
return new MyRequestParamsGatewayFilter(config);
}
}
4、配置IP网关过滤器
# TODO 基于 【BFF-AUTH】 服务的路由配置
- id: BFF-AUTH-ROUTE
uri: lb://bffAuth
predicates:
- Path=/springCloudGateway/auth/**
filters:
# 自定义 [MyIpGatewayFilter] 网关过滤器。*表示允许所有ip请求,其它格式为:127.0.0.1,192.168.0.110
- MyIp=127.0.0.1,192.168.1.1
# 自定义 [MyRequestParamsGatewayFilter] 过滤器。参数1:是否打印请求参数,参数2:是否解密请求参数
- MyRequestParams=Y,Y
文章来源地址https://www.toymoban.com/news/detail-627919.html
文章来源:https://www.toymoban.com/news/detail-627919.html
到了这里,关于SpringCloudGateway过滤器(全局认证、IP拦截、请求参数过滤、响应参数过滤)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!