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