思路:
- gateway网关过滤器中将用户信息添加到请求头中
- 被转发的服务中,写一个拦截器,拦截所有请求,获取请求头的用户信息,存入到threadLocal中
- 拦截器在请求结束时清除threadLocal中的内容
1.网关过滤器
package pers.darcy.flower.gateway.service.filter;
/**
* @author wqf
* @date 2021/07/11
* 类描述:全局过滤器 用于处理用户鉴权的等
*/ 省略无关代码
@Slf4j
@Component
public class CustomerGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
...
//.白名单请求校验 ...
//请求合法性校验 ...
//token合法性校验 ..
//用户权限校验 ...
Claims claims = JwtTokenUtil.parseToken(accessToken, privateKey);//解密jwt token 获取用户信息
//以下两行代码表示把token放入请求头中
ServerHttpRequest shr = request.mutate().header("TokenInfo", JSON.toJSONString(claims )).build();
exchange.mutate().request(shr).build();
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
}
2.拦截器代码如下
@Slf4j
public class UserInterceptor implements HandlerInterceptor {
/**
* 服务间调用的认证token
*/
public static final String TOKEN_INFO = "TokenInfo";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
String userInfo = request.getHeader(TOKEN_INFO);
TokenInfo tokenInfo = JSONUtil.toBean(userInfo, TokenInfo.class);//TokenInfo 存储用户信息的实体类
UserContext.getInstance().setContext(tokenInfo);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
UserContext.getInstance().clear();
}
}
3.注册拦截器
/**
* 类说明: 拦截器注册
*
* @author wqf
* @date 2022/2/23 13:49
*/
@Configuration
public class WebServerMvcConfigurerAdapter implements WebMvcConfigurer {
@Bean
public HandlerInterceptor userInterceptor() {
return new UserInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(userInterceptor());
}
}
工具类
package pers.darcy.flower.utils.util;
import pers.darcy.flower.utils.domain.token.TokenInfo;
/**
* @author yao
* @date 2021/6/28 11:01
*/
public class UserContext {
private ThreadLocal<TokenInfo> threadLocal;
private UserContext() {
this.threadLocal = new ThreadLocal<>();
}
/**
* 创建实例
*/
public static UserContext getInstance() {
return SingletonContext.S_INSTANCE;
}
/**
* 静态内部类单例模式
* 单例初使化
*/
private static class SingletonContext {
private static final UserContext S_INSTANCE = new UserContext();
}
/**
* 用户上下文中放入信息
*/
public void setContext(TokenInfo tokenInfo) {
threadLocal.set(tokenInfo);
}
/**
* 获取上下文中的信息
*/
public TokenInfo getContext() {
return threadLocal.get();
}
/**
* 获取上下文中的用户名
*/
public String getUsername() {
return getContext().getUsername();
}
/**
* 获取上下文中的用户id
*/
public Long getUserId() {
return getContext().getId();
}
/**
* 清空上下文
*/
public void clear() {
threadLocal.remove();
}
}
微服务中每个服务都需要配置拦截器,可以把拦截器部分代码方法公共代码模块,其他工程引入即可
PS:接下来可以去了解feign远程调用的token传递
以上仅供参考
网友评论