定义ContextHolder

ContextHolder用来寄存和获取线程变量中的 用户id、用户名称、Token等信息。

/** * 获取以后线程变量中的 用户id、用户名称、Token等信息 * 留神: 必须在网关通过申请头的办法传入,同时在Interceptor拦截器设置值。 否则这里无奈获取 * * */public class SecurityContextHolder{    private static final TransmittableThreadLocal<Map<String, Object>> THREAD_LOCAL = new TransmittableThreadLocal<>();    public static void set(String key, Object value)    {        Map<String, Object> map = getLocalMap();        map.put(key, value == null ? StringUtils.EMPTY : value);    }    public static String get(String key)    {        Map<String, Object> map = getLocalMap();        return Convert.toStr(map.getOrDefault(key, StringUtils.EMPTY));    }    public static <T> T get(String key, Class<T> clazz)    {        Map<String, Object> map = getLocalMap();        return StringUtils.cast(map.getOrDefault(key, null));    }    public static Map<String, Object> getLocalMap()    {        Map<String, Object> map = THREAD_LOCAL.get();        if (map == null)        {            map = new ConcurrentHashMap<String, Object>();            THREAD_LOCAL.set(map);        }        return map;    }    public static void setLocalMap(Map<String, Object> threadLocalMap)    {        THREAD_LOCAL.set(threadLocalMap);    }    public static String  getUserId()    {        return  get(SecurityConstants.DETAILS_USER_ID);    }    public static void setUserId(String account)    {        set(SecurityConstants.DETAILS_USER_ID, account);    }    public static String getUserName()    {        return get(SecurityConstants.DETAILS_USERNAME);    }    public static void setUserName(String username)    {        set(SecurityConstants.DETAILS_USERNAME, username);    }    public static String getUserKey()    {        return get(SecurityConstants.USER_KEY);    }    public static void setUserKey(String userKey)    {        set(SecurityConstants.USER_KEY, userKey);    }    public static void remove()    {        THREAD_LOCAL.remove();    }    public static void setUserType(String userType) {        set(SecurityConstants.USER_TYPE, userType);    }    public static String getUserType()    {        return get(SecurityConstants.USER_TYPE);    }}

利用模块的拦截器寄存登录信息

@Componentpublic class SjcjInterceptor implements HandlerInterceptor {    @Autowired    private RemoteUserService remoteUserService;    @Autowired    private TokenService tokenService;    //超管的id=1    @Value("${admin.userId:1}")    private String adminUserId;        @Override    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {        if (!(handler instanceof HandlerMethod)) {            return true;        }        String userId = SecurityContextHolder.getUserId();        if(StringUtils.isEmpty(userId)){            userId = adminUserId;            R<LoginUser> userResult = remoteUserService.getUserIdInfo(userId, SecurityConstants.INNER);            if (R.FAIL == userResult.getCode())            {                throw new ServiceException(userResult.getMsg());            }            LoginUser userInfo = userResult.getData();            Map<String, Object> rspMap = tokenService.createToken(userInfo, 1);            SecurityContextHolder.setUserId(userInfo.getUserid());            SecurityContextHolder.setUserName(userInfo.getUsername());            SecurityContextHolder.set(SecurityConstants.LOGIN_USER, userInfo);            SecurityContextHolder.set(SecurityConstants.AUTHORIZATION_HEADER,rspMap.get("access_token"));        }        return true;    }    }

feign 申请拦截器

该拦截器从申请requst取用户信息,或者从SecurityContextHolder取登录信息,并保留到RequestTemplate。

/** * feign 申请拦截器 * * */@Componentpublic class FeignRequestInterceptor implements RequestInterceptor{    @Override    public void apply(RequestTemplate requestTemplate)    {        HttpServletRequest httpServletRequest = ServletUtils.getRequest();        if (StringUtils.isNotNull(httpServletRequest))        {            Map<String, String> headers = ServletUtils.getHeaders(httpServletRequest);            // 传递用户信息申请头,避免失落            String userId = headers.get(SecurityConstants.DETAILS_USER_ID);            //cjq 2022/10/12            //从request没取到,则从SecurityContextHolder从取            //适应于无前端的状况,在接口调用前,把用户信息放到SecurityContextHolder            if(StringUtils.isEmpty(userId)){                userId = SecurityContextHolder.get(SecurityConstants.DETAILS_USER_ID);            }            if (StringUtils.isNotEmpty(userId))            {                requestTemplate.header(SecurityConstants.DETAILS_USER_ID, userId);            }            String userName = headers.get(SecurityConstants.DETAILS_USERNAME);            if (StringUtils.isEmpty(userName)){                userName = SecurityContextHolder.get(SecurityConstants.DETAILS_USERNAME);            }            if (StringUtils.isNotEmpty(userName))            {                requestTemplate.header(SecurityConstants.DETAILS_USERNAME, userName);            }            String authentication = headers.get(SecurityConstants.AUTHORIZATION_HEADER);            if (StringUtils.isNotEmpty(authentication)){                authentication = SecurityContextHolder.get(SecurityConstants.AUTHORIZATION_HEADER);            }            if (StringUtils.isNotEmpty(authentication))            {                requestTemplate.header(SecurityConstants.AUTHORIZATION_HEADER, authentication);            }            // 配置客户端IP            requestTemplate.header("X-Forwarded-For", IpUtils.getIpAddr(ServletUtils.getRequest()));        }    }}

模块间调用服务api,就能够取到设置的用户登录信息了。

能够应用SecurityContextHolder获取相干的信息了。