共计 4238 个字符,预计需要花费 11 分钟才能阅读完成。
定义 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);
}
}
利用模块的拦截器寄存登录信息
@Component
public 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 申请拦截器
*
*
*/
@Component
public 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 获取相干的信息了。
正文完