一、简介
网关是一个服务: Spring Cloud GateWay是Spring Cloud的?个全新项?,?标是取代Netflix Zuul,基于Spring5.0+SpringBoot2.0+WebFlux(基于?性能的Reactor模式响应式通信框架Netty,异步?阻塞模型)等技术开发,性能?于Zuul,官?测试,GateWay是Zuul的1.6倍,旨在为微服务架构提供?种简单有效的统?的API路由管理?式。
二、开始使用
1.引入包(gateway)????????
<!-- 网关 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- 负载均衡 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
2. 配置nacos进行服务注册和发现
? ? ? ? 描述:使用nacos+gateway实现各模块服务的负载均衡
? ? ? ? nacos的配置使用可以参考文章:
????????SpringCloud:注册中心nacos_Cx_轩的博客-CSDN博客
3..yml配置
spring:
application:
name: Cx-gateway
cloud:
gateway:
httpclient:
connect-timeout: 90000 #连接超时 毫秒
response-timeout: 90s #应答超时 java.time.Duration http状态码504
discovery:
locator:
enabled: false # 启用探测器 默认false,开启后可以通过ip:port/服务名称/接口地址进行服务转发
lower-case-service-id: true # 路由名小写
routes:
- id: Cx-admin # admin后台
uri: lb://Cx-admin
predicates:
- Path=/admin/**
filters:
- StripPrefix=1 # 过滤前缀 admin
- id: Cx-es # es服务
uri: lb://Cx-es
predicates:
- Path=/es/**
filters:
- StripPrefix=1 # 过滤前缀 es
此处对predicates断言进行使用描述:(常用的几种列举出来方便大家参考)
1.Path路径断言
predicates:
-Path=/xx # 拦截此路径下的所有请求发送到网关配置的uri (以一个模块一个路径去区分)
2.Query断言
predicates:
-Query=name,age. #参数值可以写正则,也可以只写参数名
3.Method断言
predicates:
-Method=get
4.Host断言
predicates:
-Host=xxxx.com
5.Cookie断言
predicates:
-Cookie=user,Cx #cookie断言和上面介绍的几种断言方式都大同小异,唯一不同的是他必须连同属性值一起验证,不能单独只验证属性是否存在
6.Header断言
predicates:
-Header=id,1234\d+ # 正则表达式\d+ 数字,header断言是检查头信息里是否携带了相关属性或令牌
7.时间路由
predicates:
- After=2022-02-07T17:05:00.789+08:00[Asia/Shanghai] # 时间匹配有三种模式,分别是Before、After和Between,指定了在什么时间范围内路由才会生效
三、网关+单点登录使用
1.使用jwt生成无状态token令牌,然后在网关项目中进行auth验证。
2.创建网关全局拦截
@Configuration
@Component
@Slf4j
public class AuthFilter implements GlobalFilter,Ordered {
private static final String AUTHORIZE_TOKEN = "token";
private static AntPathMatcher matcher = new AntPathMatcher();
@Override
public int getOrder() {
return 0;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String url = request.getPath().toString();
log.info("【登录拦截】获取请求地址路径:"+url);
// 不需要拦截的url直接通过
if(isNotAuth(url)){
return chain.filter(exchange);
}
String token = request.getHeaders().getFirst(AUTHORIZE_TOKEN);
if(StrUtil.isBlank(token)){
token = request.getQueryParams().getFirst(AUTHORIZE_TOKEN);
}
if(StrUtil.isBlank(token)){
log.info("【登录拦截】未获取到token值...");
loginResponse(exchange);
}
log.debug("【登录拦截】获取token值:"+token);
try {
SSOToken ssoToken = SSOToken.parser(token);
// 获取token中的用户名
String userId = ssoToken.getId();
log.info("【登录拦截】获取userId:"+userId);
} catch (Exception e) {
log.error("【登录拦截】异常:"+e.getMessage());
return loginResponse(exchange);
}
return chain.filter(exchange);
}
public static Mono<Void> loginResponse(ServerWebExchange exchange) {
JSONObject json = JSONUtil.createObj();
json.set("code", 401);
json.set("msg", "请重新登陆授权");
ServerHttpResponse response = exchange.getResponse();
byte[] bytes = JSONUtil.toJsonStr(json).getBytes(StandardCharsets.UTF_8);
//指定编码,否则在浏览器中会中文乱码
response.getHeaders().add("Content-Type", "text/plain;charset=UTF-8");
DataBuffer buffer = response.bufferFactory().wrap(bytes);
return response.writeWith(Flux.just(buffer));
}
private boolean isNotAuth(String url) {
List<String> uriList = new ArrayList<>();
// admin后台不需要拦截
uriList.add("/admin/**");
uriList.add("/sso/login");
for (String pattern : uriList) {
if (matcher.match(pattern, url)) {
// 不需要拦截
return true;
}
}
return false;
}
}
上述代码中SSOToken就是jwt的封装,大家可以直接使用jwt进行解析即可。
注:此处使用jwt无状态token令牌,为了方便不同模块、不同前端项目针对不同ip和端口部署的分布式应用时在进行用户验权时可以不需要考虑会话session和cookie只需要将token存储在浏览器中即可全局使用。在访问时只校验token的有效性。所以在使用jwt的token时可以降低token的有效时长在增加安全性。
|