文章目录
前言
前端请求不能直接访问微服务,而是要请求网关(SpringCloudGateway)
网关干什么?路由过滤,登录校验。
nacos既是注册中心也可用作配置管理,用来解决各个微服务块配置文件中相同的配置冗余,配置热更新属性,动态路由等。
一、网关路由
数据在网络间传输,从一个网络传输到另一网络时就需要经过网关来做数据的路由和转发以及数据安全的校验。
微服务中的网关作用:前端请求不能直接访问微服务,而是要请求网关。
- 网关可以做安全控制,也就是登录身份校验,校验通过才放行
- 通过认证后,网关再根据请求判断应该访问哪个微服务,将请求转发过去
二、SpringCloudGateway
网关本身也是一个独立的微服务,所以也需要单独建立一个模块。实现步骤:
- 创建网关微服务模块
- 引入SpringCloudGateway、NacosDiscovery依赖
- 编写启动类
- 配置网关路由
1. 路由过滤
spring:
cloud:
gateway:
routes:
- id: item
uri: lb://item-service
predicates:
- Path=/items/**,/search/** #请求路径必须符合指定规则
RouteDefinition就是具体的路由规则定义。
- id:路由的唯一标示
- predicates:路由断言,其实就是匹配条件
- filters:路由过滤条件
- uri:路由目标地址,lb://代表负载均衡,从注册中心获取目标微服务的实例列表,并且负载均衡选择一个访问。
2. 网关登录校验
2.1 鉴权
在网关中保存密钥开发登录校验功能
问题
1、怎么在转发之前做登录校验
2、校验JWT之后,怎么把用户信息传递给微服务
3、微服务之间怎么传递用户信息
2.2 网关过滤器
实现原理
- 客户端请求进入网关后由HandlerMapping对请求做判断,找到与当前请求匹配的路由规则(Route),然后将请求交给WebHandler去处理。
- WebHandler则会加载当前路由下需要执行的过滤器链(Filter chain),然后按照顺序逐一执行过滤器(后面称为Filter)。
- 图中Filter被虚线分为左右两部分,是因为Filter内部的逻辑分为pre和post两部分,分别会在请求路由到微服务之前和之后被执行。
- 只有所有Filter的pre逻辑都依次顺序执行通过后,请求才会被路由到微服务。
- 微服务返回结果后,再倒序执行Filter的post逻辑。
- 最终把响应结果返回。
定义一个过滤器,在其中实现登录校验逻辑,并且将过滤器执行顺序定义到NettyRoutingFilter之前?
网关过滤器
- GatewayFilter:路由过滤器,作用范围比较灵活,可以是任意指定的路由Route.
- GlobalFilter:全局过滤器,作用范围是所有路由,不可配置。FilteringWebHandler在处理请求时,会将GlobalFilter装饰为GatewayFilter,然后放到同一个过滤器链中,排序以后依次执行。
- AddRequestHeaderGatewayFilterFacotry: 就是添加请求头的过滤器,可以给请求添加一个请求头并传递到下游微服务。直接在yaml文件中配置
1、自定义GatewayFilter
定义一个类,这个类的名称一定要以GatewayFilterFactory为后缀,这个类继承了AbstractGatewayFilterFactory
2、自定义GlobalFilter
定义一个类,直接实现GlobalFilter接口。
2.3 登录校验
2.3.1 JWT
- AuthProperties:配置登录校验需要拦截的路径,因为不是所有的路径都需要登录才能访问
- JwtProperties:定义与JWT工具有关的属性,比如秘钥文件位置
- SecurityConfig:工具的自动装配
- JwtTool:JWT工具,其中包含了校验和解析token的功能
- hmall.jks:秘钥文件
2.3.2 登录校验过滤器
定义一个登录校验的过滤器,实现GlobalFilter接口。
@Component
@RequiredArgsConstructor
@EnableConfigurationProperties(AuthProperties.class)
public class AuthGlobalFilter implements GlobalFilter, Ordered {
private final JwtTool jwtTool;
private final AuthProperties authProperties;
private final AntPathMatcher antPathMatcher = new AntPathMatcher();
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1.获取Request
ServerHttpRequest request = exchange.getRequest();
// 2.判断是否不需要拦截
if(isExclude(request.getPath().toString())){
// 无需拦截,直接放行
return chain.filter(exchange);
}
// 3.获取请求头中的token
String token = null;
List<String> headers = request.getHeaders().get("authorization");
if (!CollUtils.isEmpty(headers)) {
token = headers.get(0);
}
// 4.校验并解析token
Long userId = null;
try {
userId = jwtTool.parseToken(token);
} catch (UnauthorizedException e) {
// 如果无效,拦截
ServerHttpResponse response = exchange.getResponse();
response.setRawStatusCode(401);
return response.setComplete();
}
// TODO 5.如果有效,传递用户信息
//保存用户请求头
String userInfo