在Spring Cloud微服務架構中,多個服務協同工作時,經常需要在服務調用鏈路中傳遞用戶上下文信息(如用戶ID、角色、權限等),以確保業務邏輯的一致性與安全性。本文將重點探討如何利用Spring Cloud Gateway(作為統一入口)與OpenFeign(作為服務間HTTP客戶端)組件,設計一套高效、安全的用戶信息傳遞方案。
微服務拆分為獨立進程后,傳統的基于線程本地變量(如ThreadLocal)的用戶信息存儲方式不再適用,因為每次服務調用都可能跨越網絡邊界。主要挑戰包括:
業界常見且成熟的方案是通過HTTP請求頭(Header)進行用戶信息的透傳。整體流程如下圖所示(邏輯描述):
userId、username等)以特定請求頭(如X-User-Info)的形式放入轉發請求中。RequestContextHolder或自定義上下文),供業務邏輯使用。在Gateway中定義全局過濾器(GlobalFilter),在認證成功后,將用戶信息序列化后放入請求頭。建議對信息進行加密或使用簽名,防止篡改。
@Component
public class UserInfoTransmitFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1. 從認證信息中提取用戶詳情 (例如從JWT中解析)
String userId = ...; // 解析邏輯
String userName = ...;
// 2. 構造用戶信息對象或字符串 (可JSON序列化)
UserInfo userInfo = new UserInfo(userId, userName);
String userInfoJson = JSON.toJSONString(userInfo);
// 3. 將信息放入請求頭,轉發給下游服務
ServerHttpRequest request = exchange.getRequest().mutate()
.header("X-User-Info", userInfoJson) // 可使用Base64編碼或加密
.build();
return chain.filter(exchange.mutate().request(request).build());
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE + 1; // 確保在認證過濾器之后執行
}
}
定義Feign的RequestInterceptor,確保在服務A通過Feign調用服務B時,能將當前HTTP請求上下文中的用戶信息頭,自動附加到新的Feign請求上。
@Component
public class FeignUserInfoInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
// 從當前請求上下文中獲取網關傳入的用戶信息頭 (適用于Servlet環境)
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes != null) {
HttpServletRequest request = attributes.getRequest();
String userInfoHeader = request.getHeader("X-User-Info");
if (StringUtils.hasText(userInfoHeader)) {
// 將頭信息原樣傳遞給下游服務
template.header("X-User-Info", userInfoHeader);
}
}
}
}
注意:若微服務使用WebFlux(響應式),需使用ReactiveRequestContextHolder來獲取請求上下文。
在每個微服務內部,需定義一個過濾器(Servlet的Filter或Spring的HandlerInterceptor),在請求進入業務控制器之前,從X-User-Info頭中解析出用戶信息,并將其存儲到當前請求的上下文中。
@Component
public class ParseUserInfoFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
String userInfoHeader = request.getHeader("X-User-Info");
if (StringUtils.hasText(userInfoHeader)) {
// 解密/解碼,反序列化
UserInfo userInfo = JSON.parseObject(userInfoHeader, UserInfo.class);
// 存儲到當前請求上下文,例如使用ThreadLocal
UserContextHolder.set(userInfo);
}
try {
chain.doFilter(request, response);
} finally {
// 請求結束后清理上下文,防止內存泄漏
UserContextHolder.clear();
}
}
}
其中UserContextHolder是一個基于ThreadLocal的工具類,用于在當前線程內存取用戶信息。
ServerWebExchange的屬性中,避免在后續過濾器中重復解析。@Async,線程池),需將ThreadLocal中的用戶信息手動傳遞到子線程。可考慮使用InheritableThreadLocal或阿里開源的TransmittableThreadLocal。通過結合Spring Cloud Gateway的前置過濾器與OpenFeign的請求攔截器,構建一個基于HTTP請求頭的用戶信息透傳管道,是實現微服務間用戶上下文無縫傳遞的經典模式。該方案對業務代碼侵入性小,與Spring Cloud組件集成度高。在實際企業級應用中,應重點關注信息的安全性(加密/簽名)、傳遞的可靠性以及異步場景下的上下文管理,并輔以完善的監控,從而構建出安全、健壯、可維護的微服務通信基礎設施。
如若轉載,請注明出處:http://www.any100.cn/product/38.html
更新時間:2026-03-17 23:49:20