प्रौद्योगिकी साझेदारी

springboot इत्यस्मिन् threadlocal इत्यस्य उपयोगः उपयोक्तृपरिचयसूचनाः filter इत्यत्र संग्रहीतुं भवति ।

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

अस्मिन् लेखे मुख्यतया springboot इत्यस्य फ़िल्टरवर्गस्य माध्यमेन परिचयसूचनाः रक्षितुं फ़िल्टर् मध्ये jwt सूचनां सेट् कर्तुं पद्धतिः वर्णिता अस्ति ।
प्रक्रिया: अनुरोध->छननम्->अनुरोध-शरीर-सूचनाः पार्स->थ्रेड्-लोकल-मध्ये स्थापयन्तु

फ़िल्टर परिभाषयतु: Servlet विनिर्देशस्य उपयोगेन एकः फ़िल्टर (Filter), यः /api मार्गेण सह मेलनं कुर्वन्तः सर्वान् HTTP अनुरोधाः अवरुद्ध्य @WebFilter टिप्पणीद्वारा पञ्जीकृतः भवति ।

@WebFilter("/api") टिप्पणी निर्दिशति यत् /api मार्गं अभिगच्छन्तीषु सर्वेषु अनुरोधेषु फ़िल्टरः प्रयुक्तः भविष्यति ।
@घटक टिप्पणी: .

@Component Spring framework इत्यस्य एनोटेशनम् अस्ति, यत् सूचयति यत् JwtFilter एकः Spring घटकः अस्ति यः Spring container द्वारा प्रबन्धयितुं शक्यते तथा च निर्भरता injection इत्यस्य समर्थनं करोति ।
doFilter विधिः : १.
doFilter विधिः परिभाषयति यत् फ़िल्टर Servlet अथवा Servlet पात्रे प्रविशन्तं अनुरोधं प्रतिक्रियां च कथं अवरुद्ध्य संसाधयति ।
विधिहस्ताक्षरम् : १.

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

एषा पद्धतिः त्रीणि मापदण्डानि स्वीकुर्वति: ServletRequest अनुरोधः, ServletResponse प्रतिक्रिया तथा FilterChain श्रृङ्खला ।
इदं IOException अथवा ServletException क्षिप्तुं शक्नोति ।
अनुरोधः प्रतिक्रिया च : १.

doFilter पद्धतेः प्रथमद्वयं पैरामीटर् वर्तमानं अनुरोधं प्रतिक्रियावस्तुं च प्रतिनिधियति भवान् अनुरोधदत्तांशं पठितुं शक्नोति तथा च अस्मिन् पद्धत्या अनुरोधं प्रतिक्रियां च परिवर्तयितुं शक्नोति ।
सामान्यतया, doFilter पद्धतेः अन्ते, फ़िल्टर श्रृङ्खलायां अग्रिमस्य फ़िल्टरस्य अथवा लक्ष्यसंसाधनस्य निष्पादनं निरन्तरं कर्तुं chain.doFilter(request, response) इति आह्वयितुं आवश्यकम् ।

यदि भवान् अनुरोधसामग्रीम् पुनः परिवर्तयितुम् इच्छति तर्हि HttpServletRequestWrapper इत्यस्य उपयोगं कर्तुं शक्नोति HttpServletRequestWrapper एकः रैपरवर्गः अस्ति यः HttpServletRequest अन्तरफलकं विस्तारयति, यत् भवान् अनुरोधसंसाधनं परिवर्तयितुं वा विस्तारयितुं वा शक्नोति । HttpServletRequestUriWrapper इत्यस्य उपयोगस्य उद्देश्यं (यत् कस्टम् रैपरवर्गः भवितुम् अर्हति यः HttpServletRequestWrapper इत्यस्मात् उत्तराधिकारं प्राप्नोति) सामान्यतया अन्तर्भवति:

अनुरोधं परिवर्तयन्तु URI:

भवान् अनुरोध URI परिवर्तनं कर्तुम् इच्छति, परन्तु मूल HttpServletRequest वस्तु न । HttpServletRequestUriWrapper इत्यस्य उपयोगेन, भवान् मूलनिवेदनं लपेट्य परिवर्तितं URI प्रदातुं शक्नोति ।
मूलनिवेदनं अपरिवर्तितं स्थापयन्तु : १.

रैपरस्य उपयोगेन मूल-अनुरोध-वस्तु अपरिवर्तितं भवति, यदा तु फ़िल्टरिंग्-शृङ्खलायां कस्मिन्चित् बिन्दौ अनुरोधस्य कतिपयान् पक्षान् परिवर्तयितुं शक्यते
छाननं पूर्वसंसाधनं च : १.

filterChain.doFilter इत्येतत् आह्वयितुं पूर्वं, भवान् doFilter पद्धत्या किमपि पूर्वसंसाधनतर्कं योजयितुं शक्नोति, यथा अनुरोधमापदण्डान् परिवर्तयितुं, अनुरोधमार्गान् परिवर्तयितुं, अनुरोधशीर्षकाणि योजयितुं वा परिवर्तनं वा इत्यादीनि

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参数,并存入threadLocal管理
        var jwtInfo = JwtUtil.getJwtInfoFromReq(requestBodyPayload);
        JwtUtil.setJwtInfo(jwtInfo);

        // 读取过body,需要重新设置body
        var wrapper = new HttpServletRequestUriWrapper(httpRequest, httpRequest.getRequestURI(), requestBodyPayload);

        // 将请求传递到下一个过滤器(或者最终到达控制器方法)
        filterChain.doFilter(wrapper, servletResponse);
    }

    @Override
    public void destroy() {
        JwtUtil.removeJwtInfo();
        MDC.clear();
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

jwt सूचना: १.

@Slf4j
@Component
public class JwtUtil {

    /** 线程jwt信息维护 */
    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,转为jwtInfo对象
          
            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("请求requestId")
        private String requestId;


        @JsonPropertyDescription("请求的Region")
        private String region;
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77

jwt इत्यत्र सामग्रीं प्राप्य अन्ये http अनुरोधाः प्रेषयन्तु:

   public static JsonNode sendHttpRequest(String method, String action, String url, Map<String, Object> body)
            throws IOException, InterruptedException {

        // 设置通用参数
        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());
        }

        // 设置action
        body.put("Action", action);

        // 发送http请求,拿到请求结果
        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格式返回结果,并解析
        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("错误码:[%s],错误信息:[%s]", errorCode, errorMessage));
        }
        return jsonResponse;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33