在网关解析出用户的 Token 得到用户 ID,然后将用户 ID 添加到请求头中传递下去,由于每个服务中都需要用到此功能,所以我们将此功能在公共组件中实现
实现方案
1.聚合bff服务解析 JWT Token 后得到 UserID,修改 Spring Cloud Gateway 的请求头,将 UserID 添加到请求头中。
@RequiredArgsConstructor
@Slf4j
@Component
public class TransmitUserInfoFeignClientInterceptor implements RequestInterceptor {
private final AccountService accountService;
@Override
public void apply(RequestTemplate requestTemplate) {
//从应用上下文中取出user信息,放入Feign的请求头中
LoginUser currentLoginUser = accountService.getCurrentLoginUser();
if (currentLoginUser != null) {
String userJson = JSON.toJSONString(currentLoginUser);
try {
requestTemplate.header("KEY_USERINFO_IN_HTTP_HEADER", URLEncoder.encode(userJson, "UTF-8"));
} catch (UnsupportedEncodingException e) {
log.error("URL encode error", e);
}
}
}
}
2.自定义用户上下文 UserInfoContext,并使用 ThreadLocal 进行存储。
public class UserInfoContext {
private static ThreadLocal<UserInfo> userInfo = new ThreadLocal<UserInfo>();
public UserInfoContext() {
}
public static UserInfo getUser(){
return userInfo.get();
}
public static void setUser(UserInfo user){
userInfo.set(user);
}
public static void removeUser() {
userInfo.remove();
}
}
@Data
public class UserInfo {
/**
* 用户主键
*/
private Long id;
/**
* 员工ID
*/
private String employeeId;
/**
* 员工名称
*/
private String name;
/**
* 登录账号名
*/
private String loginAccount;
/**
* 数据权限
*/
private List<String> pathList;
}
3.在微服务中的 Web 组件中创建拦截器 UserTokenInterceptor,从 Request 中获取 UserID,并将其添加到用户上下文 UserContextHolder 中。
@Slf4j
public class UserTokenInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler) throws Exception {
String userJson = request.getHeader("KEY_USERINFO_IN_HTTP_HEADER");
if (!StringUtils.isEmpty(userJson)) {
try {
userJson = URLDecoder.decode(userJson,"UTF-8");
UserInfo userInfo = JSON.parseObject(userJson,UserInfo.class);
//将UserInfo放入上下文中
UserInfoContext.setUser(userInfo);
} catch (UnsupportedEncodingException e) {
log.error("init userInfo error",e);
}
}
return true;
}
@Override
public void afterCompletion(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler, Exception ex) throws Exception {
UserInfoContext.removeUser();
}
}
4.将拦截器 UserInterceptor 注册到 Spring 容器中。
@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(userInterceptor())
.addPathPatterns("/**");
}
@Bean
public HandlerInterceptor userInterceptor() {
return new UserTokenInterceptor();
}
}
5.获取用户信息
@Operation(summary = "用户测试接口")
@PostMapping("/api/pd/customer/info")
public void info() {
UserInfo currentUser=UserInfoContext.getUser()
log.info("当前登录用户:" + currentUser);
}