微服务中用户信息传递的解决方案

2022-02-23  本文已影响0人  无我_无他_有你

思路:

  1. gateway网关过滤器中将用户信息添加到请求头中
  2. 被转发的服务中,写一个拦截器,拦截所有请求,获取请求头的用户信息,存入到threadLocal中
  3. 拦截器在请求结束时清除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传递

以上仅供参考

上一篇 下一篇

猜你喜欢

热点阅读