一,实现思路


1,基于JWT令牌登陆方式

  • JWT实现登录的,登录信息就保存在请求头的token中。因此要获取当前登录用户,只要获取请求头,解析其中的token。

1),Gateway网关拦截,解析用户信息

  • 我们的把token解析的行为放到了网关中,然后网关把用户信息放入请求头,传递给下游微服务。
    • 在Gateway网关中创建一个Filter,拦截并解析JWT,将用户消息放入请求头中
    • @Componentpublic class AccountAuthFilter implements GlobalFilter, Ordered {private final AuthUtil authUtil;private final AuthProperties authProperties;private final AntPathMatcher antPathMatcher = new AntPathMatcher();public AccountAuthFilter(AuthUtil authUtil, AuthProperties authProperties) {this.authUtil = authUtil;this.authProperties = authProperties;}@Overridepublic Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 1.获取请求request信息ServerHttpRequest request = exchange.getRequest();String method = request.getMethodValue();String path = request.getPath().toString();String antPath = method + ":" + path;// 2.判断是否是无需登录的路径if(isExcludePath(antPath)){// 直接放行return chain.filter(exchange);}// 3.尝试获取用户信息List authHeaders = exchange.getRequest().getHeaders().get(AUTHORIZATION_HEADER);String token = authHeaders == null ? "" : authHeaders.get(0);R r = authUtil.parseToken(token);// 4.如果用户是登录状态,尝试更新请求头,传递用户信息if(r.success()){exchange.mutate().request(builder -> builder.header(自定义请求头名称, r.getData().getUserId().toString())).build();}// 6.放行return chain.filter(exchange);}private boolean isExcludePath(String antPath) {for (String pathPattern : authProperties.getExcludePath()) {if(antPathMatcher.match(pathPattern, antPath)){return true;}}return false;}@Overridepublic int getOrder() {return 1000;}}

2),微服务获取用户信息,并将用户信息放入ThreadLocal中

每个微服务都定义一个Filter,获取用户信息。并使用ThreadLocal 将用户信息放入ThreadLocal中,每个微服务都定义很麻烦,所以我们将Filter抽取出来。

@Slf4jpublic class UserInfoInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 1.尝试获取头信息中的用户信息String authorization = request.getHeader(请求头名称);// 2.判断是否为空因为很多微服务不需要获取用户信息我们不需要拦截if (authorization == null) {return true;}// 3.转为用户id并保存try {Long userId = Long.valueOf(authorization);UserContext.setUser(userId);return true;} catch (NumberFormatException e) {log.error("用户身份信息格式不正确,{}, 原因:{}", authorization, e.getMessage());return true;}}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 清理用户信息UserContext.removeUser();}}