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

springboot在filter中如何用threadlocal存放用戶身份信息

 更新時(shí)間:2024年07月11日 11:32:03   作者:march?of?Time  
這篇文章主要介紹了springboot中在filter中如何用threadlocal存放用戶身份信息,本文章主要描述通過springboot的filter類,在過濾器中設(shè)置jwt信息進(jìn)行身份信息保存的方法,需要的朋友可以參考下

本文章主要描述通過springboot的filter類,在過濾器中設(shè)置jwt信息進(jìn)行身份信息保存的方法
流程:請(qǐng)求->過濾器->解析請(qǐng)求的body信息->放入threadlocal中

定義filter:一個(gè)使用 Servlet 規(guī)范的過濾器(Filter),它通過 @WebFilter 注解注冊(cè)為攔截所有匹配 /api 路徑的 HTTP 請(qǐng)求。

@WebFilter(“/api”) 注解指定了過濾器將應(yīng)用于所有訪問 /api路徑的請(qǐng)求。
@Component 注解:

@Component 是 Spring 框架的注解,表明 JwtFilter 是一個(gè) Spring 組件,可以被 Spring 容器管理,并支持依賴注入。
doFilter方法:
doFilter 方法定義了過濾器如何攔截和處理進(jìn)入 Servlet 或 Servlet 容器的請(qǐng)求和響應(yīng)。
方法簽名:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
    throws IOException, ServletException;

這個(gè)方法接受三個(gè)參數(shù):ServletRequest request、ServletResponse response 和 FilterChain chain。
它可能拋出 IOException 或 ServletException。
請(qǐng)求和響應(yīng):

doFilter 方法的前兩個(gè)參數(shù)代表當(dāng)前的請(qǐng)求和響應(yīng)對(duì)象,你可以在這個(gè)方法中讀取請(qǐng)求數(shù)據(jù)、修改請(qǐng)求和響應(yīng)。
通常,在 doFilter 方法的最后,你需要調(diào)用 chain.doFilter(request, response) 來繼續(xù)執(zhí)行過濾器鏈中的下一個(gè)過濾器或目標(biāo)資源。

如果要重新修改請(qǐng)求內(nèi)容,可以用HttpServletRequestWrapper,HttpServletRequestWrapper 是一個(gè)包裝器類,它擴(kuò)展了 HttpServletRequest 接口,允許你修改或擴(kuò)展請(qǐng)求的處理。使用 HttpServletRequestUriWrapper(這可能是一個(gè)自定義的包裝器類,繼承自 HttpServletRequestWrapper)的目的通常包括:

修改請(qǐng)求 URI:

你可能想要修改請(qǐng)求的 URI,但不想改變?cè)嫉?HttpServletRequest 對(duì)象。通過使用 HttpServletRequestUriWrapper,你可以包裝原始請(qǐng)求并提供一個(gè)修改后的 URI。
保持原始請(qǐng)求不變:

使用包裝器可以保持原始請(qǐng)求對(duì)象不變,同時(shí)允許你在過濾鏈中的某個(gè)點(diǎn)修改請(qǐng)求的某些方面。
過濾和預(yù)處理:

在調(diào)用 filterChain.doFilter 之前,你可以在 doFilter 方法中添加任何預(yù)處理邏輯,例如修改請(qǐng)求參數(shù)、更改請(qǐng)求路徑、添加或修改請(qǐng)求頭等。

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
@WebFilter("/api")
@Component
@Slf4j
public class JwtFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) {
        // noting to do
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {
        var httpRequest = (HttpServletRequest) servletRequest;
        var requestBodyPayload = StreamUtils.copyToString(servletRequest.getInputStream(), StandardCharsets.UTF_8);
        // 解析Body參數(shù),并存入threadLocal管理
        var jwtInfo = JwtUtil.getJwtInfoFromReq(requestBodyPayload);
        JwtUtil.setJwtInfo(jwtInfo);
        // 讀取過body,需要重新設(shè)置body
        var wrapper = new HttpServletRequestUriWrapper(httpRequest, httpRequest.getRequestURI(), requestBodyPayload);
        // 將請(qǐng)求傳遞到下一個(gè)過濾器(或者最終到達(dá)控制器方法)
        filterChain.doFilter(wrapper, servletResponse);
    }
    @Override
    public void destroy() {
        JwtUtil.removeJwtInfo();
        MDC.clear();
    }
}

jwt信息:

@Slf4j
@Component
public class JwtUtil {
    /** 線程jwt信息維護(hù) */
    private static final ThreadLocal<JwtInfo> REQUEST_BASE_INFO_THREAD_LOCAL = new ThreadLocal<>();
    /** 解析jwt信息 */
    public static JwtInfo getJwtInfoFromReq(String requestBodyPayload) {
        var jwtInfo = new JwtInfo();
        try {
            var requestBody = JsonUtil.getJsonNode(requestBodyPayload);
            log.info("[JwtUtil] RequestBody -> {}", requestBody);
            // 解析requestBody,轉(zhuǎn)為jwtInfo對(duì)象
            jwtInfo.setRequestId(requestBody.get("RequestId") != null ? requestBody.get("RequestId").asText() : "");
            jwtInfo.setRegion(requestBody.get("Region") != null ? requestBody.get("Region").asText() : "");
            log.info("[JwtUtil] JwtInfo -> {}", jwtInfo);
        } catch (Exception e) {
            log.error("[JwtUtil] Parse RequestBodyInfo Error, Error Message -> {}", e.getMessage(), e);
        }
        return jwtInfo;
    }
    /** 獲取jwt信息 */
    public static JwtInfo getJwtInfo() {
        var jwtInfo = REQUEST_BASE_INFO_THREAD_LOCAL.get();
        if (Objects.isNull(jwtInfo)) {
            final var requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (Objects.nonNull(requestAttributes)) {
                var requestBodyPayload = "";
                try {
                    requestBodyPayload = StreamUtils.copyToString(requestAttributes.getRequest().getInputStream(),
                            StandardCharsets.UTF_8);
                } catch (Exception e) {
                    log.error("[JwtUtil] Parse RequestBodyInfo Error, Error Message -> {}", e.getMessage());
                }
                jwtInfo = getJwtInfoFromReq(requestBodyPayload);
                setJwtInfo(jwtInfo);
            }
        }
        return jwtInfo;
    }
    /** 將jwt信息存入threadLocal中 */
    public static void setJwtInfo(JwtInfo jwtInfo) {
        REQUEST_BASE_INFO_THREAD_LOCAL.set(jwtInfo);
        // 將traceId寫入日志變量
        MDC.put("traceId", jwtInfo.getRequestId());
    }
    public static void setJwtInfo(String appId, String ownerUin) {
        var jwtInfo = new JwtUtil.JwtInfo();
        jwtInfo.setRequestId(UUID.randomUUID().toString());
        setJwtInfo(jwtInfo);
    }
    /** 從threadLocal中刪除jwt信息 */
    public static void removeJwtInfo() {
        REQUEST_BASE_INFO_THREAD_LOCAL.remove();
    }
    @Data
    public static class JwtInfo {
        @JsonPropertyDescription("請(qǐng)求requestId")
        private String requestId;
        @JsonPropertyDescription("請(qǐng)求的Region")
        private String region;
    }
}

獲得jwt中的內(nèi)容,去發(fā)送其他http請(qǐng)求:

   public static JsonNode sendHttpRequest(String method, String action, String url, Map<String, Object> body)
            throws IOException, InterruptedException {
        // 設(shè)置通用參數(shù)
        var jwtInfo = JwtUtil.getJwtInfo();
        if (jwtInfo != null) {
            body.put("RequestId", jwtInfo.getRequestId());
            body.put("AppId", Integer.valueOf(jwtInfo.getAppId()));
            body.put("Uin", jwtInfo.getUin());
            body.put("Region", jwtInfo.getRegion());
        }
        // 設(shè)置action
        body.put("Action", action);
        // 發(fā)送http請(qǐng)求,拿到請(qǐng)求結(jié)果
        HttpConnectUtil.ResponseInfo responseInfo = switch (method) {
            case "GET" -> HttpConnectUtil.sendGetByJson(url, JsonUtil.toJson(body));
            case "POST" -> HttpConnectUtil.sendPost(url, JsonUtil.toJson(body), new HashMap<>(2));
            default -> new HttpConnectUtil.ResponseInfo();
        };
        // 檢查Api3格式返回結(jié)果,并解析
        var jsonResponse = JsonUtil.getJsonNode(responseInfo.getContent()).get("Response");
        var jsonError = jsonResponse.get("Error");
        if (jsonError != null) {
            var errorCode = jsonError.get("Code").asText();
            var errorMessage = jsonError.get("Message").asText();
            throw new ApiException(ErrorCode.INTERNAL_ERROR,
                    String.format("錯(cuò)誤碼:[%s],錯(cuò)誤信息:[%s]", errorCode, errorMessage));
        }
        return jsonResponse;
    }

到此這篇關(guān)于springboot中在filter中用threadlocal存放用戶身份信息的文章就介紹到這了,更多相關(guān)springboot threadlocal存放用戶身份信息內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Mybatis增強(qiáng)版MyBatis-Flex的具體使用

    Mybatis增強(qiáng)版MyBatis-Flex的具體使用

    Mybatis-Flex一個(gè)用于增強(qiáng)MyBatis的框架,本文主要介紹了Mybatis增強(qiáng)版MyBatis-Flex的具體使用,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-06-06
  • SpringMVC中的DispatcherServlet初始化流程詳解

    SpringMVC中的DispatcherServlet初始化流程詳解

    這篇文章主要介紹了SpringMVC中的DispatcherServlet初始化流程詳解,DispatcherServlet這個(gè)前端控制器是一個(gè)Servlet,所以生命周期和普通的Servlet是差不多的,在一個(gè)Servlet初始化的時(shí)候都會(huì)調(diào)用該Servlet的init()方法,需要的朋友可以參考下
    2023-12-12
  • Java查搜索文件內(nèi)容實(shí)現(xiàn)方式

    Java查搜索文件內(nèi)容實(shí)現(xiàn)方式

    用戶為解決無法搜索文件內(nèi)容的問題,編寫了一個(gè)支持單文件、文件夾及多層遞歸查找的工具,具備字符串匹配及忽略大小寫功能,并計(jì)劃擴(kuò)展日期、創(chuàng)建人等組合搜索條件,最終打包成exe便于快速查找所有文件內(nèi)容
    2025-09-09
  • SpringBoot?自定義注解之脫敏注解詳解

    SpringBoot?自定義注解之脫敏注解詳解

    這篇文章主要介紹了SpringBoot?自定義注解之脫敏注解詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • java wait()/notify() 實(shí)現(xiàn)生產(chǎn)者消費(fèi)者模式詳解

    java wait()/notify() 實(shí)現(xiàn)生產(chǎn)者消費(fèi)者模式詳解

    這篇文章主要介紹了java wait()/notify() 實(shí)現(xiàn)生產(chǎn)者消費(fèi)者模式詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Java關(guān)于含有繼承類的成員初始化過程講解

    Java關(guān)于含有繼承類的成員初始化過程講解

    今天小編就為大家分享一篇Java關(guān)于含有繼承類的成員初始化過程講解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-04-04
  • IDEA 設(shè)置顯示內(nèi)存的使用情況和內(nèi)存回收的方法

    IDEA 設(shè)置顯示內(nèi)存的使用情況和內(nèi)存回收的方法

    這篇文章主要介紹了IDEA 設(shè)置顯示內(nèi)存的使用情況和內(nèi)存回收的方法,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-04-04
  • Spring AI對(duì)接大模型開發(fā)易錯(cuò)點(diǎn)總結(jié)與實(shí)戰(zhàn)解決辦法

    Spring AI對(duì)接大模型開發(fā)易錯(cuò)點(diǎn)總結(jié)與實(shí)戰(zhàn)解決辦法

    本文介紹了SpringAI接入大模型時(shí)常見的問題及解決方案,主要從地址配置、密鑰鑒權(quán)、模型匹配、版本依賴四大維度入手,詳細(xì)分析了各種問題的成因,并提供了實(shí)用的配置與代碼解決方案,幫助開發(fā)者快速避坑,提高開發(fā)效率,需要的朋友可以參考下
    2026-05-05
  • Java代碼混淆工具ProGuard使用指南(附有1.8以上和以下使用工具)

    Java代碼混淆工具ProGuard使用指南(附有1.8以上和以下使用工具)

    ProGuard是一個(gè)開源的Java?class文件縮小器、優(yōu)化器、混淆器和預(yù)驗(yàn)證器,它通過刪除未使用的類、字段、方法和屬性,優(yōu)化字節(jié)碼指令,并重命名類、字段和方法,使反編譯后的代碼難以理解,從而提高應(yīng)用的安全性,本文給大家詳細(xì)介紹了ProGuard使用指南,需要的朋友可以參考下
    2025-05-05
  • SSH 框架簡(jiǎn)介

    SSH 框架簡(jiǎn)介

    SSH是 struts+spring+hibernate的一個(gè)集成框架,是目前較流行的一種web應(yīng)用程序開源框架。本文給大家詳細(xì)看一下組成SSH的這三個(gè)框架
    2017-09-09

最新評(píng)論

射洪县| 乳源| 神木县| 紫阳县| 广灵县| 鄢陵县| 甘孜县| 车险| 时尚| 高台县| 武清区| 乡宁县| 平定县| 化德县| 邯郸市| 苗栗县| 东莞市| 江川县| 肃南| 天峨县| 济阳县| 上饶县| 南漳县| 郴州市| 阿拉善盟| 榆树市| 娄底市| 翁牛特旗| 双鸭山市| 斗六市| 明光市| 克拉玛依市| 米泉市| 隆回县| 布尔津县| 信阳市| 长子县| 博罗县| 丁青县| 靖安县| 刚察县|