欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringCloudGateway 網(wǎng)關(guān)登錄校驗實(shí)現(xiàn)思路

 更新時間:2024年11月11日 11:20:00   作者:cyt濤  
文章介紹了在微服務(wù)架構(gòu)中使用Spring Cloud Gateway進(jìn)行登錄校驗的方法,通過在網(wǎng)關(guān)層面進(jìn)行登錄校驗,并將用戶信息通過請求頭傳遞給下游微服務(wù),解決了每個微服務(wù)都需要獨(dú)立進(jìn)行登錄校驗的問題,此外,還討論了如何在微服務(wù)之間傳遞用戶信息

單體架構(gòu)時我們只需要完成一次用戶登錄、身份校驗,就可以在所有業(yè)務(wù)中獲取到用戶信息。而微服務(wù)拆分后,每個微服務(wù)都獨(dú)立部署,不再共享數(shù)據(jù)。也就意味著每個微服務(wù)都需要做登錄校驗,這顯然不可取。

1. 思路分析

既然網(wǎng)關(guān)是所有微服務(wù)的入口,一切請求都需要先經(jīng)過網(wǎng)關(guān)。我們完全可以把登錄校驗的工作放到網(wǎng)關(guān)去做。

不過,這里存在幾個問題:

(1)網(wǎng)關(guān)路由是配置的,請求轉(zhuǎn)發(fā)是Gateway內(nèi)部代碼,我們?nèi)绾卧谵D(zhuǎn)發(fā)之前做登錄校驗?

        可以使用網(wǎng)關(guān)過濾器。

(2)網(wǎng)關(guān)校驗JWT之后,如何將用戶信息傳遞給微服務(wù)?

        由于網(wǎng)關(guān)發(fā)送請求到微服務(wù)依然采用的是Http請求,因此我們可以將用戶信息以請求頭的方式傳遞到下游微服務(wù)。然后微服務(wù)可以從請求頭中獲取登錄用戶信息。

(3)微服務(wù)之間也會相互調(diào)用,這種調(diào)用不經(jīng)過網(wǎng)關(guān),又該如何傳遞用戶信息?

        在微服務(wù)發(fā)起調(diào)用時把用戶信息存入請求頭。

2. 登錄校驗過濾器

白名單的配置:

application.ymlapplication.properties 文件中配置不需要攔截的路徑白名單。

gateway:
  ignoreUrls:
    - /auth/login
    - /auth/register
    - /public/**

在這個示例中,/auth/login、/auth/register、/public/** 等路徑將不需要進(jìn)行登錄校驗。

package com.cyt.gateway.filter;
@Component // 聲明為Spring容器中的一個Bean
@RequiredArgsConstructor // 生成構(gòu)造方法,注入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對象,以訪問請求的相關(guān)信息
        ServerHttpRequest request = exchange.getRequest();
        // 2. 判斷請求路徑是否在白名單中(無需JWT校驗)
        if (isIgnoreUrl(request.getPath().toString())) {
            // 路徑在白名單中,直接放行請求
            return chain.filter(exchange);
        }
        // 3. 獲取請求頭中的token(假設(shè)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(); // 返回空的響應(yīng)結(jié)束處理
        }
        // TODO 5. 如果token有效,可在此處傳遞用戶信息(如通過exchange.getAttributes())
        System.out.println("userId = " + userId); // 打印用戶ID供調(diào)試
        // 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; // 設(shè)置過濾器優(yōu)先級,值越小優(yōu)先級越高
    }
}

3. 保存用戶到請求頭

5.6.部分代碼可以參照下面修改:

// 5.傳遞用戶信息
// 將解析出的用戶ID轉(zhuǎn)換為字符串,以便可以在請求頭中傳遞
String userInfo = userId.toString();
// 使用 exchange.mutate() 方法創(chuàng)建一個新的 ServerWebExchange 對象,
// 該對象將攜帶額外的請求頭 "user-info",包含用戶ID信息。
// .mutate() 方法用于復(fù)制當(dāng)前請求并進(jìn)行修改。
// 在這里,我們使用 request(builder -> builder.header(...)) 方式為請求添加一個新的頭部。
ServerWebExchange modifiedExchange = exchange.mutate()
        .request(builder -> builder.header("user-info", userInfo)) // 將 "user-info" 頭設(shè)置為用戶ID字符串
        .build(); // 完成新的 ServerWebExchange 對象的構(gòu)建
// 6.放行
// 使用修改后的 ServerWebExchange 對象繼續(xù)執(zhí)行過濾鏈。
// 這樣,下游服務(wù)可以通過 "user-info" 請求頭獲取到用戶ID信息。
return chain.filter(modifiedExchange);

4. OpenFeign傳遞用戶

在微服務(wù)發(fā)起調(diào)用時把用戶信息存入請求頭。

如何才能讓每一個由OpenFeign發(fā)起的請求自動攜帶登錄用戶信息呢?

這里要借助Feign中提供的一個攔截器接口:feign.RequestInterceptor

我們只需要實(shí)現(xiàn)這個接口,然后實(shí)現(xiàn)apply方法,利用RequestTemplate類來添加請求頭,將用戶信息保存到請求頭中。

可以在OpenFeign的配置類中添加一個Bean:

@Bean
public RequestInterceptor userInfoRequestInterceptor(){
    // 定義一個 Feign 的 RequestInterceptor Bean,用于在請求發(fā)出前執(zhí)行自定義攔截操作
    return new RequestInterceptor() {
        @Override
        public void apply(RequestTemplate template) {
            // 獲取當(dāng)前登錄用戶的ID
            // UserContext 是一個上下文工具類,用于存儲和獲取當(dāng)前線程的用戶信息
            Long userId = UserContext.getUser();
            // 檢查用戶ID是否為 null,如果為 null 則表示用戶未登錄或無法獲取用戶信息
            if(userId == null) {
                // 如果用戶ID為空,不做任何處理,直接返回,跳過攔截器邏輯
                return;
            }
            // 如果用戶ID不為空,將用戶ID作為請求頭添加到 Feign 請求中
            // "user-info" 是請求頭的鍵,下游微服務(wù)可以從該請求頭中獲取用戶ID
            template.header("user-info", userId.toString());
        }
    };
}

5. 總結(jié)

思路分析中提到的三個問題,目前已經(jīng)全部解決。

接下來,微服務(wù)需要用戶信息,只需要編寫攔截器,獲取用戶信息并保存到ThreadLocal中,然后放行即可。

由于每個微服務(wù)都有獲取登錄用戶的需求,因此攔截器可以直接寫在common公共服務(wù)中,并寫好自動裝配。這樣微服務(wù)只需要引入common就可以直接具備攔截器功能,無需重復(fù)編寫。

到此這篇關(guān)于SpringCloudGateway 網(wǎng)關(guān)登錄校驗的文章就介紹到這了,更多相關(guān)SpringCloudGateway 登錄校驗內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論