微服务之间如何通过ThreadLocal ,拦截器,过滤器 共享用户登录信息

**

微服务之间如何通过网关,ThreadLocal ,拦截器,过滤器 共享用户登录信息(例如id token信息)

**

1.在编写登录逻辑时,使用id去生成一个token

  @PostMapping("/login")
//     @RequestParam(required = false) String username, @RequestParam(required=false)  String password
    public Result<Map> login(@RequestBody User user) {
        Map<String, Object> map = new HashMap<>();
        try {
            User users = userService.login(user.getUsername(), user.getPassword());
            //生成JWT的令牌
            long id = users.getId().longValue();
            String token = AppJwtUtil.getToken(id);
            map.put("id",users.getId());
            map.put("state", true);
            map.put("msg", "认证成功");
            map.put("token", token);//响应token
            return Result.success(map);
        } catch (Exception e) {
            map.put("state", false);
            map.put("msg", e.getMessage());
            return Result.error(map);
        }
    }

2.在网关中添加filter过滤器,调用jwt工具解析token,把解析后的用户信息存储到header(一定要加上component注解)

package com.isoft.mygateway.filter;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.isoft.mygateway.utils.AppJwtUtil;
import io.jsonwebtoken.Claims;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
public class AuthorizeFilter implements Ordered, GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1.获取request和response对象
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        //2.判断是否是登录
        if (request.getURI().getPath().contains("/login")) {
            //放行
            return chain.filter(exchange);
        }
        //3.获取token
        String token = request.getHeaders().getFirst("token");
        //4.判断token是否存在
        if (StringUtils.isBlank(token)) {
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }

        //5.判断token是否有效
        try {
            Claims claimsBody = AppJwtUtil.getClaimsBody(token);
            //是否是过期
            int result = AppJwtUtil.verifyToken(claimsBody);
            if (result == 1 || result == 2) {
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                return response.setComplete();
            }

//            网关进行token解析后,把解析后的用户信息存储到header
            Object userId = claimsBody.get("id"); //这里的id 是 登录时获取token的id

//            在header中添加新的信息
            ServerHttpRequest serverHttpRequest = request.mutate().headers(httpHeaders -> {
                httpHeaders.add("userId", userId + "");
            }).build();
//            重置header
            exchange.mutate().request(serverHttpRequest).build();


        } catch (Exception e) {
            e.printStackTrace();
        }

        //6.放行
        return chain.filter(exchange);
    }

    /**
     * 优先级设置  值越小  优先级越高
     *
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}

3.在需要使用到用户信息的微服务 中使用拦截器 获取上一步中保存到请求头中的用户信息,并将其保存到ThreadLocal中(注意一定加@Component ,这里我没加找了半天错!!!真的栓q)

package com.isoft.mymodule.interceptor;

import com.heima.utils.common.BaseContext;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.C;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Optional;

@Slf4j
@Component
public class TokenInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String userId = request.getHeader("userId");
        Optional<String> optional = Optional.ofNullable(userId);
        if (optional.isPresent()) {
//            把id存入threadLocal
            Long id = Long.valueOf(userId);
            BaseContext.setCurrentId(id);
            log.info("设置用户信息到ThreadLocal中:{}", userId);
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("清理threadLocal");
        //一定要清理,要不然可能会发生内存泄漏
        BaseContext.clear();
    }
}

4.在当前微服务中配置3中的拦截器

package com.isoft.mymodule.config;

import com.isoft.mymodule.interceptor.TokenInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

//配置类
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new TokenInterceptor()).addPathPatterns("/**");
    }

    //映射静态资源目录
//    @Override
//    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
//        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
//        registry.addResourceHandler("/templates/**").addResourceLocations("classpath:/templates/");
//    }


}

5.这样就ok,进行测试 ,编写的接口如下:

   @GetMapping("/showMyContract")
    public Result<MyContract> showMyContract() {
        MyContract myContract = myContractService.getById(BaseContext.getCurrentId());
        return Result.success(myContract);
    }

6.测试结果
首先登录,获取token
在这里插入图片描述
我的模块 微服务 查询操作
在这里插入图片描述

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值