一.思路总结
前端发起请求到网关,由网关完成登录校验,并将用户id存入请求头中,然后在注册中心中获取微服务的信息,然后发送请求到微服务,其中拦截器拦截到该请求,获得用户信息并存入线程空间中,之后发送请求到微服务。服务返回结果给前端,然后释放线程空间。
那么问题来了?
token如何传递到前端?
不同微服务之间如何传递用户信息?
第一个问题:网关有断言,首先排除掉登录请求,然后请求发送到登录服务中。登录成功之后后端返回JWT给前端。
第二个问题:我们通过openfeign来实现微服务之间的远程调用。我们需要将用户信息存入请求头中。但是openfeign的请求发送是自动的,所以我们应该怎么办呢?oepenFeign为我们提供了RequestInterceptor拦截器。我们只要实现其中的方法,将用户id注入拦截器中即可。

本文重点探讨网关相关的操作
二.配置网关路由
1.引入依赖
<!--common-->
<dependency>
<groupId>com.heima</groupId>
<artifactId>hm-common</artifactId>
<version>1.0.0</version>
</dependency>
<!--网关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--nacos discovery-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--负载均衡-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
2.编写启动类
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
3.配置路由
server:
port: 8080
spring:
application:
name: gateway
cloud:
nacos:
server-addr: 192.168.150.101:8848
gateway:
routes:
- id: item # 路由规则id,自定义,唯一
uri: lb://item-service # 路由的目标服务,lb代表负载均衡,会从注册中心拉取服务列表
predicates: # 路由断言,判断当前请求是否符合当前规则,符合则路由到目标服务
- Path=/items/**,/search/** # 这里是以请求路径作为判断规则
- id: cart
uri: lb://cart-service
predicates:
- Path=/carts/**
- id: user
uri: lb://user-service
predicates:
- Path=/users/**,/addresses/**
- id: trade
uri: lb://trade-service
predicates:
- Path=/orders/**
- id: pay
uri: lb://pay-service
predicates:
- Path=/pay-orders/**
三.网关登录校验
1.定义全局过滤器实现用户登录校验
@RequiredArgsConstructor
public class AuthGlobalFilter implements GlobalFilter, Ordered {
private final JwtTool jwtTool;
private final AuthProperties authProperties;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//获取请求
ServerHttpRequest request = exchange.getRequest();
//判断是否放行
RequestPath path = request.getPath();
if(include( path)){
return chain.filter(exchange);
}
//获取token
String token = request.getHeaders().getFirst("Authorization");
//校验并解析token
String userId = null;
try {
//校验成功将用户信息存入请求头中,放行
userId = jwtTool.parseToken(token).toString();
} catch (Exception e) {
//校验失败返回401
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
ServerWebExchange ex = exchange.mutate()
.request(request.mutate().header("user", userId).build())
.build();
return chain.filter(ex);
}
private boolean include(RequestPath path) {
if (authProperties.getExcludePaths().contains(path.toString())){
return true;
}
return false;
}
@Override
public int getOrder() {
return 0;
}
}
2.重写RequestInterceptor实现微服务之间的用户id传递
@Configuration
public class DefaultOprnfeignConfig {
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
@Bean
public RequestInterceptor requestInterceptor() {
return new RequestInterceptor() {
@Override
public void apply(RequestTemplate requestTemplate) {
//获取用户id
Long userId = UserContext.getUser();
if (userId == null){
return;
}
requestTemplate.header("authorization", "Bearer " + "123");
}
};
}
}
四.配置管理
1.配置共享
<1>添加共享配置到Nacos
<2>添加依赖
<!--nacos配置管理-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!--读取bootstrap文件-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<3>编写配置类
hm:
db:
name: hm-item
<4>编写bookstrap拉取Nacos配置
2.配置热更新
<1>添加配置到Nacos
<2>写实体类接受参数
Data
@Component
@ConfigurationProperties(prefix = "hm.cart")
public class CartProperties {
private Integer maxAmount;
}