最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot基于攔截器與ThreadLocal實(shí)現(xiàn)用戶登錄校驗(yàn)

 更新時(shí)間:2025年12月10日 08:34:12   作者:ShaneD771  
本文介紹了一種在SpringBoot中實(shí)現(xiàn)統(tǒng)一登錄校驗(yàn)和上下文共享的解決方案,通過(guò)使用攔截器、ThreadLocal和自定義工具類,實(shí)現(xiàn)了在請(qǐng)求處理過(guò)程中優(yōu)雅地獲取當(dāng)前登錄用戶信息,并且避免了在每個(gè)Controller方法中重復(fù)編寫(xiě)校驗(yàn)代碼,需要的朋友可以參考下

1. 背景與問(wèn)題

在無(wú)狀態(tài)的 HTTP 協(xié)議下,Web 應(yīng)用通常使用 SessionToken 機(jī)制來(lái)維持用戶的登錄狀態(tài)。在 Spring Boot 后端開(kāi)發(fā)中,面臨兩個(gè)核心問(wèn)題:

  1. 統(tǒng)一校驗(yàn):如何在請(qǐng)求到達(dá)業(yè)務(wù)邏輯之前,統(tǒng)一攔截未登錄請(qǐng)求,避免在每個(gè) Controller 方法中重復(fù)編寫(xiě)校驗(yàn)代碼?
  2. 上下文共享:在 Controller、Service 甚至 Dao 層中,如何優(yōu)雅地獲取當(dāng)前登錄用戶的信息,而不需要層層傳遞 User 對(duì)象參數(shù)?

這里介紹登錄 + 攔截器 (Interceptor) + 線程本地變量 (ThreadLocal)”

2. 架構(gòu)設(shè)計(jì)

該方案的流程如下:

  1. 登錄接口:負(fù)責(zé)認(rèn)證身份,并將用戶信息存入 HttpSession。
  2. 攔截器 (preHandle):在請(qǐng)求進(jìn)入 Controller 之前攔截。校驗(yàn) Session 中是否存在用戶信息。
    • 若存在:將用戶信息讀取并存入當(dāng)前線程的 ThreadLocal 中,放行。
    • 若不存在:攔截請(qǐng)求,返回 401 狀態(tài)碼。
  3. 業(yè)務(wù)層 (Controller/Service):需要用戶信息時(shí),直接從 ThreadLocal 中獲取,無(wú)需依賴 Session API。
  4. 攔截器 (afterCompletion):請(qǐng)求結(jié)束,響應(yīng)返回前,移除 ThreadLocal 中的用戶信息,防止內(nèi)存泄漏。

3. 代碼實(shí)現(xiàn)步驟

3.1 封裝 ThreadLocal 工具類 (UserHolder)

為了在同一線程內(nèi)共享數(shù)據(jù),我們需要封裝一個(gè)基于 ThreadLocal 的工具類。它充當(dāng)了線程內(nèi)全局容器的角色。

public class UserHolder {
    // 使用 ThreadLocal 保存用戶信息,UserDTO 為脫敏后的用戶對(duì)象
    private static final ThreadLocal<UserDTO> tl = new ThreadLocal<>();

    // 保存用戶
    public static void saveUser(UserDTO user){
        tl.set(user);
    }

    // 獲取用戶
    public static UserDTO getUser(){
        return tl.get();
    }

    // 移除用戶(防止內(nèi)存泄漏的關(guān)鍵)
    public static void removeUser(){
        tl.remove();
    }
}

3.2 自定義登錄攔截器 (LoginInterceptor)

攔截器實(shí)現(xiàn) HandlerInterceptor 接口,負(fù)責(zé)“校驗(yàn)”和“上下文傳遞”。

public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 1. 獲取 Session
        HttpSession session = request.getSession();
        
        // 2. 獲取 Session 中的用戶
        Object user = session.getAttribute("user");
        
        // 3. 校驗(yàn)用戶是否存在
        if (user == null) {
            // 4. 不存在,攔截,設(shè)置狀態(tài)碼 401 (未授權(quán))
            response.setStatus(401);
            return false;
        }
        
        // 5. 存在,將用戶信息保存到 ThreadLocal
        // 這一步實(shí)現(xiàn)了從 Web 層 (Session) 到 業(yè)務(wù)層 (ThreadLocal) 的狀態(tài)轉(zhuǎn)移
        UserHolder.saveUser((UserDTO) user);
        
        // 6. 放行
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 7. 必須移除用戶,避免線程池復(fù)用導(dǎo)致的“數(shù)據(jù)串號(hào)”和內(nèi)存泄漏
        UserHolder.removeUser();
    }
}

3.3 注冊(cè)攔截器 (MvcConfig)

通過(guò)實(shí)現(xiàn) WebMvcConfigurer 接口,將自定義攔截器注冊(cè)到 Spring MVC 的攔截鏈中,并配置攔截路徑。

@Configuration
public class MvcConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .excludePathPatterns(
                        "/user/code",   // 發(fā)送驗(yàn)證碼
                        "/user/login",  // 登錄接口
                        "/blog/hot",    // 熱門(mén)博客
                        "/shop/**",     // 店鋪詳情
                        "/shop-type/**" // 店鋪類型
                ).order(1);
    }
}

3.4 業(yè)務(wù)層獲取用戶信息 (/user/me)

在 Controller 中,我們不再需要操作 HttpSessionHttpServletRequest,直接調(diào)用 UserHolder 即可。

@GetMapping("/me")
public Result me(){
    // 直接從 ThreadLocal 獲取當(dāng)前請(qǐng)求關(guān)聯(lián)的用戶信息
    UserDTO user = UserHolder.getUser();
    return Result.ok(user);
}

4. 組件關(guān)系

這套機(jī)制中,各組件的職責(zé)與關(guān)系如下:

4.1 攔截器 (Interceptor) 與 Session 的關(guān)系

  • 關(guān)系讀取者與存儲(chǔ)者
  • 解析:Session 是由 Tomcat 容器管理的服務(wù)器內(nèi)存存儲(chǔ)。攔截器作為請(qǐng)求處理的第一道關(guān)卡,負(fù)責(zé)從 Session 中讀取狀態(tài)。攔截器并不產(chǎn)生用戶數(shù)據(jù),它只是校驗(yàn) Session 中是否已由登錄接口寫(xiě)入了數(shù)據(jù)。

4.2 攔截器 (Interceptor) 與 ThreadLocal 的關(guān)系

  • 關(guān)系生產(chǎn)者與容器
  • 解析:這是本架構(gòu)最精妙的地方。攔截器在 preHandle 階段充當(dāng)“搬運(yùn)工”,將 Session 中的數(shù)據(jù)(Web 作用域)復(fù)制到 ThreadLocal(線程作用域)。這使得后續(xù)的 Service 層代碼可以完全脫離 javax.servlet API,實(shí)現(xiàn)了業(yè)務(wù)邏輯與 Web 容器的解耦。

4.3 Controller/Service 與 ThreadLocal 的關(guān)系

  • 關(guān)系消費(fèi)者與容器。
  • 解析:Controller 或 Service 層完全不需要知道攔截器的存在,也不需要知道數(shù)據(jù)是從 Session 來(lái)的還是 Token 來(lái)的。它們只需要信任 UserHolder,認(rèn)為“只要代碼執(zhí)行到這里,UserHolder 里一定有當(dāng)前用戶”,從而簡(jiǎn)化了代碼邏輯。

5. 總結(jié)

實(shí)現(xiàn)這套登錄校驗(yàn)攔截機(jī)制,本質(zhì)上是為了解決兩個(gè)工程化問(wèn)題:

  1. 安全性(Secur11ity):通過(guò)攔截器實(shí)現(xiàn)統(tǒng)一的權(quán)限控制,防止未登錄用戶訪問(wèn)受保護(hù)資源。
  2. 代碼解耦(Decoupling):利用 ThreadLocal 替代參數(shù)傳遞,使得用戶信息可以在同一請(qǐng)求線程的任意位置被訪問(wèn),極大地提高了代碼的可維護(hù)性。

在后續(xù)的分布式演進(jìn)中(如引入 Redis),我們只需要修改 登錄接口(存 Redis)攔截器(查 Redis) 的邏輯,而業(yè)務(wù)層獲取用戶信息的代碼(UserHolder.getUser())完全不需要改動(dòng),這體現(xiàn)了良好的架構(gòu)擴(kuò)展性。

以上就是SpringBoot基于攔截器與ThreadLocal實(shí)現(xiàn)用戶登錄校驗(yàn)的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot用戶登錄校驗(yàn)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 基于@ComponentScan注解及其XML配置方式

    基于@ComponentScan注解及其XML配置方式

    這篇文章主要介紹了基于@ComponentScan注解及其XML配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • 一個(gè)簡(jiǎn)單的Java文件讀取的進(jìn)度條

    一個(gè)簡(jiǎn)單的Java文件讀取的進(jìn)度條

    這篇文章主要介紹了一個(gè)簡(jiǎn)單的Java文件讀取的進(jìn)度條,寫(xiě)一個(gè)可以使用的?demo,涉及到了文件的相對(duì)路徑問(wèn)題,需要的朋友可以參考下
    2023-04-04
  • 一文綜合對(duì)比分析JDK?8、JDK?17和JDK?19

    一文綜合對(duì)比分析JDK?8、JDK?17和JDK?19

    Java是一門(mén)非常流行的編程語(yǔ)言,由于其跨平臺(tái)性、可移植性以及強(qiáng)大的面向?qū)ο筇匦远鴤涫芮嗖A,這篇文章主要介紹了JDK?8、JDK?17和JDK?19綜合對(duì)比分析的相關(guān)資料,文中介紹的非常詳細(xì),需要的朋友可以參考下
    2026-01-01
  • SpringBoot自定義bean綁定實(shí)現(xiàn)

    SpringBoot自定義bean綁定實(shí)現(xiàn)

    這篇文章主要介紹了SpringBoot自定義bean綁定,最常見(jiàn)的配置綁定的場(chǎng)景,是在自定義的bean中通過(guò)@Value注解將某個(gè)屬性和對(duì)應(yīng)的配置綁定
    2022-10-10
  • 關(guān)于Struts2文件上傳與自定義攔截器

    關(guān)于Struts2文件上傳與自定義攔截器

    本篇文章,小編將為大家介紹關(guān)于Struts2文件上傳與自定義攔截器,有需要的朋友可以參考一下
    2013-04-04
  • java 生成二維碼實(shí)例

    java 生成二維碼實(shí)例

    這篇文章主要介紹了java 生成二維碼的實(shí)例,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • java創(chuàng)建txt文件并寫(xiě)入內(nèi)容的方法代碼示例

    java創(chuàng)建txt文件并寫(xiě)入內(nèi)容的方法代碼示例

    這篇文章主要介紹了java創(chuàng)建txt文件并寫(xiě)入內(nèi)容的兩種方法,分別是使用java.io.FileWriter和BufferedWriter,以及使用Java7的java.nio.file包中的Files和Path類,需要的朋友可以參考下
    2025-01-01
  • java中的equals()和toString()方法實(shí)例詳解

    java中的equals()和toString()方法實(shí)例詳解

    這篇文章主要介紹了java中的equals()和toString()方法實(shí)例詳解的相關(guān)資料,這里舉例說(shuō)明,并附實(shí)例代碼,和實(shí)現(xiàn)效果圖,需要的朋友可以參考下
    2016-11-11
  • Java中的幾種讀取properties配置文件的方式

    Java中的幾種讀取properties配置文件的方式

    這篇文章主要介紹了Java中的幾種讀取properties配置文件的方式,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-05-05
  • mybatis 根據(jù)id批量刪除的實(shí)現(xiàn)操作

    mybatis 根據(jù)id批量刪除的實(shí)現(xiàn)操作

    這篇文章主要介紹了mybatis 根據(jù)id批量刪除的實(shí)現(xiàn)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-08-08

最新評(píng)論

大关县| 凯里市| 峨边| 宝鸡市| 阿拉善盟| 滕州市| 武胜县| 龙南县| 广丰县| 乳源| 遂宁市| 玉山县| 阿巴嘎旗| 丹棱县| 农安县| 托克逊县| 江安县| 鱼台县| 宝清县| 永修县| 青冈县| 阜康市| 彩票| 万荣县| 柘荣县| 襄汾县| 潞城市| 日照市| 宝坻区| 独山县| 乌恰县| 牙克石市| 高州市| 略阳县| 鹿泉市| 大连市| 新津县| 建昌县| 肥西县| 武强县| 易门县|