SpringCloudGateway 網(wǎng)關登錄校驗實現(xiàn)思路
單體架構時我們只需要完成一次用戶登錄、身份校驗,就可以在所有業(yè)務中獲取到用戶信息。而微服務拆分后,每個微服務都獨立部署,不再共享數(shù)據(jù)。也就意味著每個微服務都需要做登錄校驗,這顯然不可取。
1. 思路分析
既然網(wǎng)關是所有微服務的入口,一切請求都需要先經(jīng)過網(wǎng)關。我們完全可以把登錄校驗的工作放到網(wǎng)關去做。
不過,這里存在幾個問題:
(1)網(wǎng)關路由是配置的,請求轉發(fā)是Gateway內部代碼,我們如何在轉發(fā)之前做登錄校驗?
可以使用網(wǎng)關過濾器。
(2)網(wǎng)關校驗JWT之后,如何將用戶信息傳遞給微服務?
由于網(wǎng)關發(fā)送請求到微服務依然采用的是Http
請求,因此我們可以將用戶信息以請求頭的方式傳遞到下游微服務。然后微服務可以從請求頭中獲取登錄用戶信息。
(3)微服務之間也會相互調用,這種調用不經(jīng)過網(wǎng)關,又該如何傳遞用戶信息?
在微服務發(fā)起調用時把用戶信息存入請求頭。
2. 登錄校驗過濾器
白名單的配置:
在 application.yml
或 application.properties
文件中配置不需要攔截的路徑白名單。
gateway: ignoreUrls: - /auth/login - /auth/register - /public/**
在這個示例中,/auth/login
、/auth/register
、/public/**
等路徑將不需要進行登錄校驗。
package com.cyt.gateway.filter; @Component // 聲明為Spring容器中的一個Bean @RequiredArgsConstructor // 生成構造方法,注入final成員變量 @EnableConfigurationProperties(AuthProperties.class) // 啟用配置類AuthProperties的屬性注入 public class AuthGlobalFilter implements GlobalFilter, Ordered { // 從配置文件中注入白名單路徑列表,用于存放不需要JWT校驗的路徑 @Value("${gateway.ignoreUrls}") private List<String> ignoreUrls; private final JwtTool jwtTool; // JWT工具類,用于解析和校驗JWT @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // 1. 獲取Request對象,以訪問請求的相關信息 ServerHttpRequest request = exchange.getRequest(); // 2. 判斷請求路徑是否在白名單中(無需JWT校驗) if (isIgnoreUrl(request.getPath().toString())) { // 路徑在白名單中,直接放行請求 return chain.filter(exchange); } // 3. 獲取請求頭中的token(假設token放在"authorization"頭部) String token = null; List<String> headers = request.getHeaders().get("authorization"); if (!CollUtils.isEmpty(headers)) { // 如果請求頭包含authorization字段 token = headers.get(0); // 獲取第一個token值 } // 4. 使用jwtTool校驗并解析token Long userId = null; try { userId = jwtTool.parseToken(token); // 解析并獲取用戶ID } catch (UnauthorizedException e) { // 如果token無效或解析失敗,則返回401狀態(tài)碼并攔截請求 ServerHttpResponse response = exchange.getResponse(); response.setRawStatusCode(401); return response.setComplete(); // 返回空的響應結束處理 } // TODO 5. 如果token有效,可在此處傳遞用戶信息(如通過exchange.getAttributes()) System.out.println("userId = " + userId); // 打印用戶ID供調試 // 6. 放行請求 return chain.filter(exchange); } /** * 判斷路徑是否在白名單中 * * @param path 請求路徑 * @return 如果路徑在白名單中返回true,否則返回false */ private boolean isIgnoreUrl(String path) { for (String ignoreUrl : ignoreUrls) { // 使用正則匹配白名單路徑中的通配符 "**" if (path.matches(ignoreUrl.replace("**", ".*"))) { return true; // 路徑匹配白名單中的某一項,返回true } } return false; // 沒有匹配到任何白名單路徑,返回false } @Override public int getOrder() { return 0; // 設置過濾器優(yōu)先級,值越小優(yōu)先級越高 } }
3. 保存用戶到請求頭
5.6.部分代碼可以參照下面修改:
// 5.傳遞用戶信息 // 將解析出的用戶ID轉換為字符串,以便可以在請求頭中傳遞 String userInfo = userId.toString(); // 使用 exchange.mutate() 方法創(chuàng)建一個新的 ServerWebExchange 對象, // 該對象將攜帶額外的請求頭 "user-info",包含用戶ID信息。 // .mutate() 方法用于復制當前請求并進行修改。 // 在這里,我們使用 request(builder -> builder.header(...)) 方式為請求添加一個新的頭部。 ServerWebExchange modifiedExchange = exchange.mutate() .request(builder -> builder.header("user-info", userInfo)) // 將 "user-info" 頭設置為用戶ID字符串 .build(); // 完成新的 ServerWebExchange 對象的構建 // 6.放行 // 使用修改后的 ServerWebExchange 對象繼續(xù)執(zhí)行過濾鏈。 // 這樣,下游服務可以通過 "user-info" 請求頭獲取到用戶ID信息。 return chain.filter(modifiedExchange);
4. OpenFeign傳遞用戶
在微服務發(fā)起調用時把用戶信息存入請求頭。
如何才能讓每一個由OpenFeign發(fā)起的請求自動攜帶登錄用戶信息呢?
這里要借助Feign中提供的一個攔截器接口:feign.RequestInterceptor
我們只需要實現(xiàn)這個接口,然后實現(xiàn)apply方法,利用RequestTemplate
類來添加請求頭,將用戶信息保存到請求頭中。
可以在OpenFeign的配置類中添加一個Bean:
@Bean public RequestInterceptor userInfoRequestInterceptor(){ // 定義一個 Feign 的 RequestInterceptor Bean,用于在請求發(fā)出前執(zhí)行自定義攔截操作 return new RequestInterceptor() { @Override public void apply(RequestTemplate template) { // 獲取當前登錄用戶的ID // UserContext 是一個上下文工具類,用于存儲和獲取當前線程的用戶信息 Long userId = UserContext.getUser(); // 檢查用戶ID是否為 null,如果為 null 則表示用戶未登錄或無法獲取用戶信息 if(userId == null) { // 如果用戶ID為空,不做任何處理,直接返回,跳過攔截器邏輯 return; } // 如果用戶ID不為空,將用戶ID作為請求頭添加到 Feign 請求中 // "user-info" 是請求頭的鍵,下游微服務可以從該請求頭中獲取用戶ID template.header("user-info", userId.toString()); } }; }
5. 總結
思路分析中提到的三個問題,目前已經(jīng)全部解決。
接下來,微服務需要用戶信息,只需要編寫攔截器,獲取用戶信息并保存到ThreadLocal中,然后放行即可。
由于每個微服務都有獲取登錄用戶的需求,因此攔截器可以直接寫在common公共服務
中,并寫好自動裝配。這樣微服務只需要引入common
就可以直接具備攔截器功能,無需重復編寫。
到此這篇關于SpringCloudGateway 網(wǎng)關登錄校驗的文章就介紹到這了,更多相關SpringCloudGateway 登錄校驗內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java中Random簡介_動力節(jié)點Java學院整理
本文詳細給大家介紹了Java中Random簡介相關知識,非常不錯,具有參考借鑒價值,需要的朋友參考下吧2017-06-06詳解Spring數(shù)據(jù)緩存注解@Cacheable、@CachePut、@CacheEvict
這篇文章主要介紹了詳解Spring數(shù)據(jù)緩存注解@Cacheable、CachePut、@CacheEvict,當以一組參數(shù)第一次調用某個方法時,返回值會被保存在緩存中,如果這個方法再次以相同的參數(shù)進行調用時,這個返回值會從緩存中查詢獲取,需要的朋友可以參考下2023-07-07將一個數(shù)組按照固定大小進行拆分成數(shù)組的方法
下面小編就為大家?guī)硪黄獙⒁粋€數(shù)組按照固定大小進行拆分成數(shù)組的方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-11-11關于@PostConstruct、afterPropertiesSet和init-method的執(zhí)行順序
這篇文章主要介紹了關于@PostConstruct、afterPropertiesSet和init-method的執(zhí)行順序,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09