文章目录

  • 前言
  • 一、项目结构
  • 二、步骤
    • 1.pom.xml
    • 2.java代码
  • 总结

前言

最近搞了一套网关校验,路由分发模块,这里分享出来给大家


提示:以下是本篇文章正文内容,下面案例可供参考

一、项目结构

二、步骤

1.pom.xml

代码如下(示例):

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.liaozhiwei</groupId><artifactId>gateway</artifactId><version>0.0.1-SNAPSHOT</version><name>gateway</name><description>gateway</description><properties><java.version>1.8</java.version></properties><parent><artifactId>liaozhiwei</artifactId><groupId>com.liaozhiwei</groupId><version>1.0.0</version></parent><dependencies>
<!--        网关配置--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId><version>2.2.3.RELEASE</version></dependency>
<!--        spring cloud gateway是基于webflux的,如果非要web支持的话需要导入spring-boot-starter-webflux而不是spring-boot-start-web。--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency>
<!--        负载均衡器--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency><!--        负载--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-ribbon</artifactId></dependency><!-- nacos 依赖 开始--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId><version>2.2.3.RELEASE</version></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId><version>2.2.3.RELEASE</version></dependency><!-- nacos 依赖 结束-->
<!--        熔断--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId><version>2.0.1.RELEASE</version></dependency>
<!--        缓存配置--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.13</version><scope>compile</scope></dependency><!--添加jwt相关的包开始--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-api</artifactId><version>0.10.5</version></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-impl</artifactId><version>0.10.5</version><scope>runtime</scope></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-jackson</artifactId><version>0.10.5</version><scope>runtime</scope></dependency><!--添加jwt相关的包结束-->
<!--        springboot程序的监控系统,可以实现健康检查,info信息--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency><groupId>org.json</groupId><artifactId>json</artifactId><version>20180130</version></dependency></dependencies><build><finalName>gateway</finalName><plugins><!-- 打包生成fat jar --><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.3.4.RELEASE</version><configuration><mainClass>com.gateway.GatewayApplication</mainClass></configuration><executions><execution><phase>package</phase><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build></project>

2.java代码

IErrorCode

package com.gateway.api;/*** 封装API的错误码*/
public interface IErrorCode {Integer getCode();String getMessage();
}

ResultCode

package com.gateway.api;/*** 枚举了一些常用API操作码*/
public enum ResultCode implements IErrorCode {SUCCESS(200, "操作成功"),FAILED(500, "操作失败"),VALIDATE_FAILED(404, "参数检验失败"),UNAUTHORIZED(401, "暂未登录或token已经过期"),AUTHORIZATION_HEADER_IS_EMPTY(600,"请求头中的token为空"),GET_TOKEN_KEY_ERROR(601,"远程获取TokenKey异常"),GEN_PUBLIC_KEY_ERROR(602,"生成公钥异常"),JWT_TOKEN_EXPIRE(603,"token校验异常"),TOMANY_REQUEST_ERROR(429,"后端服务触发流控"),BACKGROUD_DEGRADE_ERROR(604,"后端服务触发降级"),BAD_GATEWAY(502,"网关服务异常"),FORBIDDEN(403, "没有相关权限"),TOKEN_VALIDATE_FAILED(504, "token校验失败,请重新登录刷新token");private Integer code;private String message;private ResultCode(Integer code, String message) {this.code = code;this.message = message;}public Integer getCode() {return code;}public String getMessage() {return message;}
}

ResultData

package com.gateway.api;import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;@Data
@NoArgsConstructor
public class ResultData<T> implements Serializable {/*** 状态码*/public boolean status = true;/*** 状态码*/private Integer code = 200;/*** 接口返回信息*/private String msg;/*** 数据对象*/private T data;/*** 初始化一个新创建的 ResultData 对象** @param status 状态码* @param msg    返回内容*/public ResultData(Boolean status, String msg) {this.status = status;this.msg = msg;}/*** 初始化一个新创建的 ResultData 对象** @param status 状态码* @param msg    返回内容* @param data   数据对象*/public ResultData(Boolean status, String msg, T data, Integer code) {this.status = status;this.msg = msg;this.data = data;this.code = code;}public ResultData(T data) {this.data = data;}/*** 返回成功消息** @param msg  返回内容* @param data 数据对象* @return 成功消息*/public static <T> ResultData<T> success(String msg, T data) {return new ResultData<T>(true, msg, data, 200);}/*** 返回成功消息** @param msg 返回内容* @return 成功消息*/public static <T> ResultData<T> success(String msg) {return ResultData.success(msg, null);}/*** 返回成功消息** @return 成功消息*/public static <T> ResultData<T> success() {return ResultData.success(null);}/*** 返回成功数据** @return 成功消息*/public static <T> ResultData<T> success(T data) {return ResultData.success(null, data);}/*** 返回错误消息** @return*/public static <T> ResultData<T> error() {return ResultData.error(null);}/*** 返回错误消息** @param msg 返回内容* @return 警告消息*/public static <T> ResultData<T> error(String msg) {return ResultData.error(msg, null);}/*** 返回错误消息** @param code 状态码* @param msg  返回内容* @return 警告消息*/public static <T> ResultData<T> error(Integer code, String msg) {return new ResultData<T>(false, msg, null, code);}/*** 返回错误消息** @param msg  返回内容* @param data 数据对象* @return 警告消息*/public static <T> ResultData<T> error(String msg, T data) {return new ResultData<T>(false, msg, data, 500);}
}

RedisConfig

/*** Copyright (c) 2016-2019 人人开源 All rights reserved.** https://www.renren.io** 版权所有,侵权必究!*/package com.gateway.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.serializer.StringRedisSerializer;/*** Redis配置** @author zhiwei liao*/
@Configuration
public class RedisConfig {@Autowiredprivate RedisConnectionFactory factory;@Beanpublic RedisTemplate<String, Object> redisTemplate() {RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setHashValueSerializer(new StringRedisSerializer());redisTemplate.setValueSerializer(new StringRedisSerializer());redisTemplate.setConnectionFactory(factory);return redisTemplate;}@Beanpublic HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {return redisTemplate.opsForHash();}@Beanpublic ValueOperations<String, String> valueOperations(RedisTemplate<String, String> redisTemplate) {return redisTemplate.opsForValue();}@Beanpublic ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {return redisTemplate.opsForList();}@Beanpublic SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {return redisTemplate.opsForSet();}@Beanpublic ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {return redisTemplate.opsForZSet();}
}

RibbonConfig

package com.gateway.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;import java.util.Collections;@Configuration
public class RibbonConfig {@Autowiredprivate LoadBalancerClient loadBalancer;@Bean//@LoadBalanced     SmartInitializingSingleton   InitializingBean (构建bean的init方法)// 顺序的问题 SmartInitializingSingleton是在所有的非懒加载单例bean构建完成之后调用的public RestTemplate restTemplate(){RestTemplate restTemplate = new RestTemplate();restTemplate.setInterceptors(Collections.singletonList(new LoadBalancerInterceptor(loadBalancer)));return restTemplate;}}

ApplicationConstant

package com.gateway.constant;/*** @Description 应用常量* @Author zhiwei Liao* @Date 2021/6/15 11:06**/
public class ApplicationConstant {//本地环境public static final String LOCAL_ENVIRONMENT = "local";//开发环境public static final String DEV_ENVIRONMENT = "dev";//测试环境public static final String UAT_ENVIRONMENT = "uat";//正式环境public static final String PRO_ENVIRONMENT = "pro";//public static final String UAT2_ENVIRONMENT = "uat2";
}

GateWayConstant

package com.gateway.constant;/*** @author zhiwei Liao* @version 1.0* @Description* @Date 2021/8/2 15:26*/public class GateWayConstant {public static final String KEY = "iA0`bN0&lKJ3{vH0(";public static final String TOKEN = "token:";public static final long TOKEN_EXPIRE_TIME = 86400000;public static final String REQUEST_TIME_BEGIN = "======请求开始时间:\n {}";public static final String REQUEST_TIME_END = "======请求开始时间:\n {}";public static final String REQUEST_GET = "=======GET请求:\n {}";public static final String REQUEST_POST = "======POST请求:\n {}";public static final String REQUEST_POST_TIME = "======POST请求:\n {}";public static final String URL_REQUIRING_AUTHENTICATION = "======需要认证的URL:{}:\n ";public static final String SKIP_CERTIFIED_URL = "======跳过认证的URL:{}:\n ";
}

GateWayException

package com.gateway.exception;import com.gateway.api.IErrorCode;
import lombok.Data;@Data
public class GateWayException extends RuntimeException{private long code;private String message;public GateWayException(IErrorCode iErrorCode) {this.code = iErrorCode.getCode();this.message = iErrorCode.getMessage();}
}

HttpResponseFilter

package com.b8.gateway.filter;import org.json.JSONTokener;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.common.utils.StringUtils;
import com.gateway.api.ResultCode;
import com.gateway.api.ResultData;
import com.gateway.constant.ApplicationConstant;
import com.gateway.constant.GateWayConstant;
import com.gateway.properties.NotAuthUrlProperties;
import com.gateway.util.JsonUtils;
import com.gateway.util.JwtUtils;
import com.gateway.util.RedisUtil;
import io.jsonwebtoken.Claims;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.factory.rewrite.CachedBodyOutputMessage;
import org.springframework.cloud.gateway.support.BodyInserterContext;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ReactiveHttpOutputMessage;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.DigestUtils;
import org.springframework.util.MultiValueMap;
import org.springframework.util.PathMatcher;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.BodyInserter;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerStrategies;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
import java.security.PublicKey;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;/*** @author zhiwei liao* @version 1.0* @Description* @Date 2021/5/21 18:30*/
@Component
@Order(0)
@EnableConfigurationProperties(value = NotAuthUrlProperties.class)
public class HttpResponseFilter implements GlobalFilter, InitializingBean {protected final static String parameterReg = "-{28}([0-9]{24})\r\n.+name=\"(\\S*)\"\r\n\r\n(\\S*)";protected final static String fileParameterReg = "-{28}([0-9]{24})\r\n.+name=\"(\\S*)\"; filename=\"(\\S*)\"\r\n.*\r\n\r\n";private Logger log = LoggerFactory.getLogger(HttpResponseFilter.class);/*** jwt的公钥,需要网关启动,远程调用认证中心去获取公钥*/private PublicKey publicKey;@Autowiredprivate RestTemplate restTemplate;/*** 请求各个微服务 不需要用户认证的URL*/@Autowiredprivate NotAuthUrlProperties notAuthUrlProperties;//开发环境:dev开发,uat测试@Value("${environment}")private String environment;@Value("${dev_environment}")private String devEnvironment;@Value("${uat_environment}")private String uatEnvironment;@Value("${uat2_environment}")private String uat2Environment;@Value("${local_environment}")private String localEnvironment;@Overridepublic void afterPropertiesSet() throws Exception {log.info("===========环境类型:" + environment);String authTokenKeyIp = null;if(environment.equals(ApplicationConstant.LOCAL_ENVIRONMENT)){authTokenKeyIp = localEnvironment;}else if(environment.equals(ApplicationConstant.DEV_ENVIRONMENT)){authTokenKeyIp = devEnvironment;}else if(environment.equals(ApplicationConstant.UAT_ENVIRONMENT)){authTokenKeyIp = uatEnvironment;}else if(environment.equals(ApplicationConstant.UAT2_ENVIRONMENT)){authTokenKeyIp = uat2Environment;}else{authTokenKeyIp = devEnvironment;}//获取公钥   http://127.0.0.1:9013/oauth/token_keythis.publicKey = JwtUtils.genPulicKey(restTemplate,authTokenKeyIp);}private boolean shouldSkip(String currentUrl) {//路径匹配器(简介SpringMvc拦截器的匹配器)//比如/oauth/** 可以匹配/oauth/token    /oauth/check_token等PathMatcher pathMatcher = new AntPathMatcher();for(String skipPath:notAuthUrlProperties.getShouldSkipUrls()) {if(pathMatcher.match(skipPath,currentUrl)) {return true;}}return false;}private ServerHttpRequest wrapHeader(ServerWebExchange serverWebExchange,Claims claims) {String loginUserInfo = JSON.toJSONString(claims);log.info("jwt的用户信息:{}",loginUserInfo);
//        String userId = claims.get("additionalInfo", Map.class).get("userId").toString();String userName = claims.get("additionalInfo",Map.class).get("userName").toString();String nickName = claims.get("additionalInfo",Map.class).get("nickName").toString();
//        String loginType = claims.get("additionalInfo",Map.class).get("loginType").toString();//向headers中放文件,记得buildServerHttpRequest request = serverWebExchange.getRequest().mutate()
//                .header("userId",userId).header("userName",userName).header("nickName",nickName)
//                .header("loginType",loginType).build();return request;}@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {log.info(GateWayConstant.REQUEST_TIME_BEGIN, new Date());ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders());//获取参数类型String contentType = exchange.getRequest().getHeaders().getFirst(HttpHeaders.CONTENT_TYPE);log.info("======content type:{}", contentType);// 解析参数OAuthRequestFactory requestFactory = new WebFluxOAuthRequestFactory();OAuthRequest authRequest = requestFactory.createRequest(exchange.getRequest());Map<String, String> requestParamsMap = new HashMap<>();exchange.getAttributes().put(GateWayConstant.REQUEST_TIME_BEGIN, System.currentTimeMillis());HttpHeaders headers = new HttpHeaders();headers.putAll(exchange.getRequest().getHeaders());headers.remove(HttpHeaders.CONTENT_LENGTH);ServerHttpRequest serverHttpRequest = exchange.getRequest();//校验请求Mono<Void> check = check(headers, exchange, serverHttpRequest);if (check != null) {log.warn("======check未通过: {}", check);return check;}//1.过滤不需要认证的url,比如/oauth/**String currentUrl = exchange.getRequest().getURI().getPath();//过滤不需要认证的urlif(shouldSkip(currentUrl)) {log.info(GateWayConstant.SKIP_CERTIFIED_URL,currentUrl);}else {log.info(GateWayConstant.URL_REQUIRING_AUTHENTICATION,currentUrl);//2. 获取token,从请求头中解析 Authorization  value:  bearer xxxxxxx或者从请求参数中解析 access_token//第一步:解析出我们Authorization的请求头  value为: “bearer XXXXXXXXXXXXXX”String authHeader = exchange.getRequest().getHeaders().getFirst("Authorization");String acceptLanguage = exchange.getRequest().getHeaders().getFirst("accept-language");//第二步:判断Authorization的请求头是否为空if(StringUtils.isEmpty(authHeader)) {log.warn("======需要认证的url,请求头为空");ResultData resultData = new ResultData();resultData.setStatus(false);resultData.setCode(HttpStatus.UNAUTHORIZED.value());String msg;if("en_us".equals(acceptLanguage)){msg = "Unauthorized";}else if("pl_pl".equals(acceptLanguage)){msg = "nieupowa?nione";}else if("zh_cn".equals(acceptLanguage)){msg = "未授权";}else {msg = "Unauthorized";}resultData.setMsg(msg);return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(Objects.requireNonNull(JsonUtils.toJson(resultData)).getBytes())));}//3. 校验token,拿到token后,通过公钥(需要从授权服务获取公钥)校验,校验失败或超时抛出异常//第三步 校验我们的jwt 若jwt不对或者超时都会抛出异常Claims claims = JwtUtils.validateJwtToken(authHeader,publicKey);if(claims == null){log.warn("======校验jwt,jwt不对");ResultData resultData = new ResultData();resultData.setStatus(false);resultData.setCode(ResultCode.TOKEN_VALIDATE_FAILED.getCode());String msg;if("en_us".equals(acceptLanguage)){msg = "token validate failed";}else if("pl_pl".equals(acceptLanguage)){msg = "token validate nie powiod?o si?";}else if("zh_cn".equals(acceptLanguage)){msg = "token校验失败";}else {msg = "token validate failed";}resultData.setMsg(msg);return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(Objects.requireNonNull(JsonUtils.toJson(resultData)).getBytes())));}//4. 校验通过后,从token中获取的用户登录信息存储到请求头中//第四步 把从jwt中解析出来的 用户登陆信息存储到请求头中ServerHttpRequest httpRequest = wrapHeader(exchange, claims);headers.putAll(httpRequest.getHeaders());}Mono<String> modifiedBody = serverRequest.bodyToMono(String.class).publishOn(Schedulers.immediate()).flatMap(originalBody -> {// 根据请求头,用不同的方式解析Bodyif (StringUtils.isNotEmpty(contentType)) {if (contentType.startsWith(MediaType.MULTIPART_FORM_DATA_VALUE)) {this.parseRequestBody(requestParamsMap, originalBody);} else if (contentType.startsWith(MediaType.APPLICATION_JSON_VALUE)) {this.parseRequestJson(requestParamsMap, originalBody);} else if (contentType.startsWith(MediaType.APPLICATION_FORM_URLENCODED_VALUE)) {this.parseRequestQuery(requestParamsMap, originalBody);}}// 加载QueryParameterthis.parseRequestQuery(requestParamsMap, exchange.getRequest().getQueryParams());log.info("所有参数:{}", JSON.toJSONString(requestParamsMap));// 把信息放置到线程容器内authRequest.setParameters(requestParamsMap);OAuthRequestContainer.set(authRequest);return Mono.just(originalBody);});log.info("所有参数:{}", JSON.toJSONString(requestParamsMap));// 把修改过的参数、消费过的参数,重新封装发布BodyInserter<Mono<String>, ReactiveHttpOutputMessage> bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class);CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, headers);Mono<Void> result = bodyInserter.insert(outputMessage, new BodyInserterContext()).then(Mono.defer(() -> {ServerHttpRequest decorator = decorate(exchange, headers, outputMessage);return chain.filter(exchange.mutate().request(decorator).build());})).onErrorResume((Function<Throwable, Mono<Void>>)throwable -> release(exchange, outputMessage, throwable));log.info(GateWayConstant.REQUEST_TIME_END, new Date());return result;}/*** 校验参数** @param headers* @return*/private Mono<Void> check(HttpHeaders headers, ServerWebExchange exchange, ServerHttpRequest serverHttpRequest) {String timestamp = headers.getFirst("timestamp");if (StringUtils.isEmpty(timestamp)) {log.info("========timestamp为空");return resultExchange(exchange);} else {log.info("=========timestamp:" + timestamp);}String acceptLanguage = headers.getFirst("accept-language");if (StringUtils.isEmpty(acceptLanguage)) {log.info("========acceptLanguage为空");return resultExchange(exchange);} else {log.info("=========acceptLanguage:" + acceptLanguage);}String vcode = headers.getFirst("vcode");if (StringUtils.isEmpty(vcode)) {log.info("========vcode为空");return resultExchange(exchange);} else {log.info("=========vcode:" + vcode);log.info("=========key:" + GateWayConstant.KEY);String keyMd5 = GateWayConstant.KEY + timestamp;String generatorVcode = DigestUtils.md5DigestAsHex(keyMd5.getBytes());log.info("=========generatorVcode:" + generatorVcode);if (!vcode.equals(generatorVcode)) {log.info("===========vcode校验不对");return resultExchange(exchange);}}//校验是否重复提交String commitRedisKey = GateWayConstant.TOKEN + vcode + serverHttpRequest.getURI().getRawPath();//加锁boolean success = RedisUtil.getLock(commitRedisKey, commitRedisKey, 1);if (!success) {log.info("=========请求太快了!请稍后再试!");return resultExchange(exchange);} else {//释放锁RedisUtil.releaseLock(commitRedisKey, commitRedisKey);}return null;}/*** @param exchange* @return Mono<Void>* @Description 定义拦截返回状态码* @Author zhiwei Liao* @Date 2021/5/21/14:56*/private Mono<Void> resultExchange(ServerWebExchange exchange) {//定义拦截返回状态码ResultData resultData = new ResultData();resultData.setStatus(false);resultData.setCode(HttpStatus.NOT_ACCEPTABLE.value());resultData.setMsg(HttpStatus.NOT_ACCEPTABLE.getReasonPhrase());return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(Objects.requireNonNull(JsonUtils.toJson(resultData)).getBytes())));}protected void parseRequestBody(Map<String, String> parameterMap, String parameterString) {this.regexParseBodyString(parameterReg, parameterMap, parameterString);this.regexParseBodyString(fileParameterReg, parameterMap, parameterString);}protected void parseRequestJson(Map<String, String> parameterMap, String parameterString) {Object json = new JSONTokener(parameterString).nextValue();if(json instanceof JSONObject){JSONObject object = (JSONObject)json;for (String key : object.keySet()) {parameterMap.put(key, object.getString(key));}}else if (json instanceof JSONArray){JSONArray jsonArray = (JSONArray)json;for (Object value : jsonArray) {parameterMap.put(null,(String)value);}}}protected void parseRequestQuery(Map<String, String> parameterMap, MultiValueMap<String, String> queryParamMap) {if (queryParamMap != null && !queryParamMap.isEmpty()) {for (String key : queryParamMap.keySet()) {final List<String> stringList = queryParamMap.get(key);parameterMap.put(key, stringList != null && !stringList.isEmpty() ? StringUtils.join(Arrays.asList(stringList.toArray()), ",") : null);}}}protected void parseRequestQuery(Map<String, String> parameterMap, String parameterString) {final String[] paramsStr = parameterString.split("&");for (String s : paramsStr) {log.info("请求名:" + s.split("=")[0]);log.info("请求值:" + s.split("=")[1]);parameterMap.put(s.split("=")[0], s.split("=")[1]);}}protected void regexParseBodyString(String reg, Map<String, String> parameterMap, String bodyStr) {Matcher matcher = Pattern.compile(reg).matcher(bodyStr);while (matcher.find()) {parameterMap.put(matcher.group(2), matcher.group(3));log.info("请求参数编号:" + matcher.group(1));log.info("请求名:" + matcher.group(2));log.info("请求值:" + matcher.group(3));}}protected ServerHttpRequestDecorator decorate(ServerWebExchange exchange, HttpHeaders headers,CachedBodyOutputMessage outputMessage) {return new ServerHttpRequestDecorator(exchange.getRequest()) {@Overridepublic 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;}@Overridepublic Flux<DataBuffer> getBody() {return outputMessage.getBody();}};}protected Mono<Void> release(ServerWebExchange exchange,CachedBodyOutputMessage outputMessage, Throwable throwable) {//        if (outputMessage.isCached()) {//            return outputMessage.getBody().map(DataBufferUtils::release)
//                    .then(Mono.error(throwable));
//        }return Mono.error(throwable);}
}

OAuthRequest

package com.gateway.filter;import java.util.Map;
import java.util.Set;public class OAuthRequest {/*** 请求参数*/private Map<String, String> parameters;/*** 请求头*/private Map<String, String> headers;/*** 请求方式:POST、GET、PUT、DELETE*/private String method;/*** 请求全路径*/private String requestURL;/*** 请求路径*/private String requestURI;/*** 请求地址参数*/private String queryString;/*** 请求来源地址*/private String remoteHost;public OAuthRequest() {}public OAuthRequest(Map<String, String> parameters, Map<String, String> headers, String method, String requestURL, String requestURI, String queryString, String remoteHost) {this.parameters = parameters;this.headers = headers;this.method = method;this.requestURL = requestURL;this.requestURI = requestURI;this.queryString = queryString;this.remoteHost = remoteHost;}/*** 获取请求参数** @param name 参数名* @return 请求参数*/public String getParameter(String name) {return parameters.get(name);}public Map<String, String> getParameters() {return parameters;}public OAuthRequest setParameters(Map<String, String> parameters) {this.parameters = parameters;return this;}/*** 获取请求头** @param name 参数名* @return 请求头信息*/public String getHeader(String name) {return headers.get(name);}public Map<String, String> getHeaders() {return headers;}public OAuthRequest setHeaders(Map<String, String> headers) {this.headers = headers;return this;}public String getMethod() {return method;}public OAuthRequest setMethod(String method) {this.method = method;return this;}public String getRequestURL() {return requestURL;}public OAuthRequest setRequestURL(String requestURL) {this.requestURL = requestURL;return this;}public String getRequestURI() {return requestURI;}public OAuthRequest setRequestURI(String requestURI) {this.requestURI = requestURI;return this;}public String getQueryString() {return queryString;}public OAuthRequest setQueryString(String queryString) {this.queryString = queryString;return this;}public String getRemoteHost() {return remoteHost;}public OAuthRequest setRemoteHost(String remoteHost) {this.remoteHost = remoteHost;return this;}public OAuthRequest narrowScope(Set<String> scope) {this.parameters.put("scope", String.join(",", scope.toArray(new String[]{})));return this;}
}

OAuthRequestContainer

package com.gateway.filter;public class OAuthRequestContainer {private static ThreadLocal<OAuthRequest> local = new InheritableThreadLocal<>();private OAuthRequestContainer() {}public static void set(OAuthRequest request) {local.set(request);}public static OAuthRequest get() {return local.get();}public static void remove() {local.remove();}public static void rewriteOAuthRequestContainer(ThreadLocal<OAuthRequest> request) {local = request;}
}

OAuthRequestFactory

package com.gateway.filter;import com.alibaba.nacos.common.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;/*** @desc: 请求解析工厂类*/
public abstract class OAuthRequestFactory {private static final Logger logger = LoggerFactory.getLogger(OAuthRequestFactory.class);/*** 构造请求实体** @param httpRequest SpringMvc下传入HttpServletRequest* @return {@link OAuthRequest} 请求实体*/public abstract OAuthRequest createRequest(Object httpRequest);/*** 构造封装请求实体** @param headers     请求头信息* @param parameters  请求参数* @param remoteHost  请求来源IP* @param method      请求方式:POST、GET...* @param requestURL  请求全路径* @param requestURI  请求路径* @param queryString 请求路径参数*/protected OAuthRequest buildRequest(Map<String, String> parameters, Map<String, String> headers, String method, String requestURL, String requestURI, String queryString, String remoteHost) {final String token = headers.get("HEADER_TOKEN.toLowerCase()");final String clientToken = headers.get("HEADER_TOKEN.toLowerCase()");// 判断是否包含认证OAuthAuthentication字段if (StringUtils.isNotEmpty(token)) {// TODO 解析令牌//final OAuthAuthentication authentication = resourceServerTokenServices.loadAuthentication(token);if (StringUtils.isNotEmpty(clientToken)) {// TODO 解析请求Client令牌}return new OAuthRequest(parameters, headers, method, requestURL, requestURI, queryString, remoteHost);}return new OAuthRequest(parameters, headers, method, requestURL, requestURI, queryString, remoteHost);}
}

WebFluxOAuthRequestFactory

package com.gateway.filter;import com.alibaba.nacos.common.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import java.net.URI;
import java.util.*;public class WebFluxOAuthRequestFactory extends OAuthRequestFactory {private static final Logger logger = LoggerFactory.getLogger(WebFluxOAuthRequestFactory.class);/*** 构造请求实体** @param httpRequest SpringMvc下传入HttpServletRequest* @return {@link OAuthRequest} 请求实体*/@Overridepublic OAuthRequest createRequest(Object httpRequest) {ServerHttpRequest request = (ServerHttpRequest) httpRequest;final String sourceIp = analysisSourceIp(request);final URI uri = request.getURI();final String url = uri.getHost() + ":" + uri.getPort() + uri.getPath() + "?" + uri.getQuery();final Map<String, String> headersMap = getHeadersMap(request);return this.buildRequest(null, headersMap, request.getMethodValue().toUpperCase(), url, uri.getPath(), uri.getQuery(), sourceIp);}/*** 获取客户端真实IP*/protected String analysisSourceIp(ServerHttpRequest request) {String ip = null;//X-Forwarded-For:Squid 服务代理String ipAddresses = request.getHeaders().getFirst("X-Forwarded-For");if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {        //Proxy-Client-IP:apache 服务代理ipAddresses = request.getHeaders().getFirst("Proxy-Client-IP");}if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {        //WL-Proxy-Client-IP:weblogic 服务代理ipAddresses = request.getHeaders().getFirst("WL-Proxy-Client-IP");}if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {        //HTTP_CLIENT_IP:有些代理服务器ipAddresses = request.getHeaders().getFirst("HTTP_CLIENT_IP");}if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {        //X-Real-IP:nginx服务代理ipAddresses = request.getHeaders().getFirst("X-Real-IP");}    //有些网络通过多层代理,那么获取到的ip就会有多个,一般都是通过逗号(,)分割开来,并且第一个ip为客户端的真实IPif (ipAddresses != null && ipAddresses.length() != 0) {ip = ipAddresses.split(",")[0];}    //还是不能获取到,最后再通过request.getRemoteAddr();获取if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {ip = Objects.requireNonNull(request.getRemoteAddress()).getHostString();}return ip;}/*** 获取所有Header信息*/private Map<String, String> getHeadersMap(ServerHttpRequest request) {final HashMap<String, String> headerMap = new HashMap<>();for (String key : request.getHeaders().keySet()) {final List<String> stringList = request.getHeaders().get(key);headerMap.put(key, stringList != null && !stringList.isEmpty() ? StringUtils.join(Arrays.asList(stringList.toArray()), ",") : null);}return headerMap;}
}

NotAuthUrlProperties

package com.gateway.properties;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;import java.util.LinkedHashSet;@Data
@ConfigurationProperties("auth.gateway")
public class NotAuthUrlProperties {private LinkedHashSet<String> shouldSkipUrls;
}

JsonUtils

/** Licensed to the Apache Software Foundation (ASF) under one or more* contributor license agreements.  See the NOTICE file distributed with* this work for additional information regarding copyright ownership.* The ASF licenses this file to You under the Apache License, Version 2.0* (the "License"); you may not use this file except in compliance with* the License.  You may obtain a copy of the License at**     http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.gateway.util;import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;/*** JsonUtils.*/
@Slf4j
public final class JsonUtils {private static final ObjectMapper MAPPER = new ObjectMapper();static {JavaTimeModule javaTimeModule = new JavaTimeModule();javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss")));MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES).disable(SerializationFeature.FAIL_ON_EMPTY_BEANS).configure(JsonParser.Feature.ALLOW_COMMENTS, true).configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true).configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true).configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true).setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).registerModule(javaTimeModule).addMixIn(Map.class, IgnoreType.class);}/*** To json string.** @param object the object* @return the string*/public static String toJson(final Object object) {try {return MAPPER.writeValueAsString(object);} catch (IOException e) {log.warn("write to json string error: " + object, e);return "{}";}}/*** Remove class object.** @param object the object* @return the object*/public static Object removeClass(final Object object) {if (object instanceof Map) {Map<?, ?> map = (Map<?, ?>) object;Object result = map.get("result");if (result instanceof Map) {Map<?, ?> resultMap = (Map<?, ?>) result;resultMap.remove("class");}map.remove("class");}return object;}@JsonIgnoreProperties("class")@interface IgnoreType {}
}

JwtUtils

package com.gateway.util;import com.gateway.api.ResultCode;
import com.gateway.exception.GateWayException;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwsHeader;
import io.jsonwebtoken.Jwt;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.springframework.http.*;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Map;@Slf4j
public class JwtUtils {/*** 认证服务器许可我们的网关的clientId(需要在oauth_client_details表中配置)*/private static final String CLIENT_ID = "b8-gateway";/*** 认证服务器许可我们的网关的client_secret(需要在oauth_client_details表中配置)*/private static final String CLIENT_SECRET = "a4d4aa1";/*** 认证服务器暴露的获取token_key的地址*/private static final String AUTH_TOKEN_KEY_URL = ":9006/oauth/token_key";/*** 请求头中的 token的开始*/private static final String AUTH_HEADER = "bearer ";public static void main(String[] args) {//密码加密方式BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();String b0h2a2 = bCryptPasswordEncoder.encode("604428249078181888");System.out.println(b0h2a2);}/*** 方法实现说明: 通过远程调用获取认证服务器颁发jwt的解析的key* @author:smlz* @param restTemplate 远程调用的操作类* @return: tokenKey 解析jwt的tokenKey* @exception:* @date:2020/1/22 11:31*/private static String getTokenKeyByRemoteCall(RestTemplate restTemplate,String ip) throws Exception {//第一步:封装请求头HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);headers.setBasicAuth(CLIENT_ID,CLIENT_SECRET);HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(null, headers);//第二步:远程调用获取token_keytry {ResponseEntity<Map> response = restTemplate.exchange(ip + AUTH_TOKEN_KEY_URL, HttpMethod.GET, entity, Map.class);String tokenKey = response.getBody().get("value").toString();log.info("去认证服务器获取Token_Key:{}",tokenKey);return tokenKey;}catch (Exception e) {log.error("远程调用认证服务器获取Token_Key失败:{}",e.getMessage());throw new Exception(ResultCode.GET_TOKEN_KEY_ERROR.getMessage());}}/*** 方法实现说明:生成公钥* @author:smlz* @param restTemplate:远程调用操作类* @return: PublicKey 公钥对象* @exception:* @date:2020/1/22 11:52*/public static PublicKey genPulicKey(RestTemplate restTemplate,String ip) throws Exception {String tokenKey = getTokenKeyByRemoteCall(restTemplate,ip);try{//把获取的公钥开头和结尾替换掉String dealTokenKey =tokenKey.replaceAll("\\-*BEGIN PUBLIC KEY\\-*", "").replaceAll("\\-*END PUBLIC KEY\\-*", "").trim();java.security.Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(dealTokenKey));KeyFactory keyFactory = KeyFactory.getInstance("RSA");PublicKey publicKey = keyFactory.generatePublic(pubKeySpec);log.info("生成公钥:{}",publicKey);return publicKey;}catch (Exception e) {log.info("生成公钥异常:{}",e.getMessage());throw new Exception(ResultCode.GEN_PUBLIC_KEY_ERROR.getMessage());}}/*** @Description 校验token* @MethodParameterTypes [java.lang.String, java.security.PublicKey]* @MethodParameters [authHeader, publicKey]* @MethodReturnType io.jsonwebtoken.Claims* @Author zhiwei Liao* @Date 2021/8/23 11:40**/public static Claims validateJwtToken(String authHeader,PublicKey publicKey) throws GateWayException {String token = null ;try{token = StringUtils.substringAfter(authHeader, AUTH_HEADER);Jwt<JwsHeader, Claims> parseClaimsJwt = Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token);Claims claims = parseClaimsJwt.getBody();log.info("claims:{}",claims);return claims;}catch(Exception e){log.error("校验token异常:{},异常信息:{}",token,e.getMessage());return null;}}
}

RedisUtil

package com.gateway.util;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisConnectionUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.Collections;/*** @author zhiwei Liao* @version 1.0* @Description* @Date 2021/8/2 16:51*/@Component
public  class RedisUtil {@Autowiredprivate RedisTemplate redisTemplate;public static RedisTemplate redis;private static final String GET_LOCK_SCRIPT = "if redis.call('setNx',KEYS[1],ARGV[1]) then if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('expire',KEYS[1],ARGV[2]) else return 0 end end";private static final String RELEASE_LOCK_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";@PostConstructpublic void getRedisTemplate(){redis = this.redisTemplate;}/*** 加锁* @param lockKey* @param value* @param expireTime  默认是秒* @return*/public static boolean getLock(String lockKey, String value, int expireTime){boolean ret = false;try{DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(GET_LOCK_SCRIPT, Long.class);Object result = RedisUtil.redis.execute(redisScript,new StringRedisSerializer(),new StringRedisSerializer(), Collections.singletonList(lockKey),value,String.valueOf(expireTime));ret = "1".equals(result.toString()) ;return ret;}catch(Exception e){e.printStackTrace();}finally {RedisConnectionUtils.unbindConnection(RedisUtil.redis.getConnectionFactory());}return ret;}/*** 释放锁* @param lockKey* @param value* @return*/public static boolean releaseLock(String lockKey, String value) {boolean ret = false;try{DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(RELEASE_LOCK_SCRIPT, Long.class);Object result = RedisUtil.redis.execute(redisScript, new StringRedisSerializer(), new StringRedisSerializer(),Collections.singletonList(lockKey), value);ret = "1".equals(result.toString()) ;}catch(Exception e){e.printStackTrace();}finally {RedisConnectionUtils.unbindConnection(RedisUtil.redis.getConnectionFactory());}return ret;}
}

B8GatewayApplication

package com.gateway;import org.springframework.boot.SpringApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;@EnableDiscoveryClient
@SpringCloudApplication
public class B8GatewayApplication {public static void main(String[] args) {SpringApplication.run(B8GatewayApplication.class, args);System.out.println("=======网关服务启动成功================");}@Bean@LoadBalancedRestTemplate restTemplate() {return new RestTemplate();}
}

bootstrap.yml

server:port: 10002
spring:mvc:async:request-timeout: 20000static-path-pattern: /**application:# 应用名称name: gatewaymain:allow-bean-definition-overriding: trueapplication_key: iA0`bN0&lK0_H0(dev_environment: http://x.xx.xx.xxx
uat_environment: http://x.xx.xx.xxx
uat2_environment: http://x.xx.xx.xxx
local_environment: http://x.xx.xx.xxxb8auth:gateway:shouldSkipUrls:- /user/xx- /xx/xx

bootstrap-uat2.yml

# Spring
spring:cloud:nacos:discovery:# 服务注册地址server-addr: ${NACOSHOST:http://xx.xx.xx.xxx}:${NACOSPORT:8034}config:# 配置中心地址server-addr: ${spring.cloud.nacos.discovery.server-addr}# 配置文件格式file-extension: yml# 共享配置shared-configs:- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}gateway:discovery:locator:enabled: falselowerCaseServiceId: trueroutes:- id: useruri: lb://userpredicates:- Path=/user/**filters:- StripPrefix=1- id: contenturi: lb://xxpredicates:- Path=/xx/**filters:- StripPrefix=1- id: contentPushuri: lb://xxpredicates:- Path=/xx/**filters:- StripPrefix=1redis:database: 0host: x.xx.xx.xxxport: 8901#  host: xx.xx.xx.xx#  port: 38764password: bU0@rR0\!dE7:*oFdfafsddfslettuce:pool:min-idle: 8max-idle: 500max-active: 2000max-wait: 10000timeout: 5000
logging:level:root: infocom.gateway: debugenvironment: uat2
application_key: i`bNdfasfasK0_lJ3{vH0(

总结

以上就是今天要讲的内容,本文仅仅简单介绍了gateway网关的实现,目前当前功能可以拿去直接上线使用,企业级,已实现路由转发,参数校验,配置中心。可以配合授权模块使用:https://liaozhiwei.blog.csdn.net/article/details/120291130 当然里面有些写死的东西,需要大家改成自个的。

Demo:第四章:Gateway网关相关推荐

  1. 【.NET Core项目实战-统一认证平台】第四章 网关篇-数据库存储配置(2)

    [.NET Core项目实战-统一认证平台]第四章 网关篇-数据库存储配置(2) 原文:[.NET Core项目实战-统一认证平台]第四章 网关篇-数据库存储配置(2) [.NET Core项目实战- ...

  2. SpringCloud Greenwich(四)注册中心之eureka、Zuul和 gateway网关配置

    本项目是搭建基于eureka注册中心的springcloud,使用zuul网关和gateway网关 一.框架搭建 (1)项目结构 eureka-server  eureka注册中心 micro-ser ...

  3. 《深入理解 Spring Cloud 与微服务构建》第十一章 服务网关

    <深入理解 Spring Cloud 与微服务构建>第十一章 服务网关 文章目录 <深入理解 Spring Cloud 与微服务构建>第十一章 服务网关 一.服务网关简介 二. ...

  4. SpringCloud系列教程(五)之SpringCloud Gateway 网关聚合开发文档 swagger knife4j 和登录权限统一验证【Hoxton版】

    阅读提醒: 本文面向的是有一定springboot基础者 本次教程使用的Spring Cloud Hoxton RELEASE版本 由于knife4j比swagger更加友好,所以本文集成knife4 ...

  5. 鸟哥的Linux私房菜(服务器)- 第四章、连上 Internet

    第四章.连上 Internet 最近更新日期:2011/07/20 终于要来到修改 Linux 网络参数的章节了!在第二章的网络基础中, 我们知道主机要连上 Internet 需要一些正确的网络参数设 ...

  6. 计算机网络总结:第四章 网络层

    第四章 网络层 4.1 概述 4.1.1 转发和路由选择 转发(forwarding):当一个分组到达路由器的一条输入链路时,路由器必须将该分组移动到适当的输出链路 路由选择(routing):当分组 ...

  7. spring cloud gateway 网关_微服务网关Spring Cloud Gateway全搞定

    一.微服务网关Spring Cloud Gateway 1.1 导引 文中内容包含:微服务网关限流10万QPS.跨域.过滤器.令牌桶算法. 在构建微服务系统中,必不可少的技术就是网关了,从早期的Zuu ...

  8. 第十一、十二、十三、十四章 网络配置管理、归档和远程复制同步文件、软件包管理、创建访问linux文件系统

    第十一章 网络配置管理 网络地址获取方式: 1)DHCP自动获取 2)手动配置 1.网卡配置文件: /etc/sysconfig/network-scripts/ [root@server0 Desk ...

  9. 第四章web服务器之httpd

    文章目录 第四章 web服务器 1.1 www简介 1.1.1 网址及HTTP简介 1.1.2 HTTP协议请求的工作流程 1.2 www服务器的类型 1.2.1 仅提供用户浏览的单向静态网页 1.2 ...

  10. 计算机网络复习题第四章(标有课本知识点)

    选择题 1.如果子网掩码是 255.255.255.224,那么主机 218.22.50.40 所在的驻留子网是( C). A.218.22.50.0 B.218.22.50.224 C.218.22 ...

最新文章

  1. Swing编程基础 之四
  2. 研发团队资源成本优化实践
  3. 数据的结构和运算(求和,最大和最小)
  4. 减少C++编译时间的方法
  5. 小程序开发(1)-之目录结构和文件说明
  6. 如何在回调中访问正确的“ this”?
  7. POJ 3046 Ant Counting ( 多重集组合数 经典DP )
  8. Get Hardware ID
  9. cocos2dx 手游luac 解密 文件的key
  10. 企业业务流程管理软件功能简介
  11. mentohust mac安装
  12. Python int()使用小结
  13. WPF Ribbon UI插件式开发框架
  14. 睿智的目标检测32——TF2搭建YoloV4目标检测平台(tensorflow2)
  15. 怎么将图片压缩到50k以内?教你一招将图片缩小的方法
  16. 决策树系列之一决策树的入门教程
  17. 用户行为分析zhi应用分析模型
  18. ROG 幻16无线网卡驱动无法更新
  19. 标签类目 知识图谱_短视频标签体系
  20. Python爬取网站数据并存入数据库(简单易懂)

热门文章

  1. 常考的java数据库笔试题
  2. FNT不能计算通用数据集(看看fwt···)
  3. 中望3D 2021 “坐标标注”
  4. 最新版 银图/网银/MOMO模拟按键/Photoshop图像处理
  5. 营业执照、组织机构代码、统一社会信用代码
  6. 【第152期】游戏策划:给@不五的简历分析
  7. 另类的切图仔画图方案:svg编辑器+css
  8. linux C 实现HTTP get 及post 请求
  9. iWebOffice2009问题
  10. Unity3D:粒子特效(Particle System)播放序列帧动画