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

基于SpringBoot實現(xiàn)HTTP請求簽名驗證機制

 更新時間:2025年04月07日 14:55:35   作者:ghostmen  
在分布式系統(tǒng)交互中,API接口的安全性至關(guān)重要,本文將深入解析基于Spring Boot實現(xiàn)的HTTP請求簽名驗證機制,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

概述

在分布式系統(tǒng)交互中,API接口的安全性至關(guān)重要。本文將深入解析基于Spring Boot實現(xiàn)的HTTP請求簽名驗證機制,該方案支持GET/POST等多種請求方式,提供時效性驗證和數(shù)據(jù)完整性保障。以下是核心實現(xiàn)的技術(shù)要點解析。

功能特性

  • 多協(xié)議支持:完整覆蓋GET、POST(JSON/Form-Data)等常見請求類型
  • 時效控制:5分鐘有效期的請求時間窗口
  • 多重驗證:公鑰校驗 + 簽名驗證 + 時間戳的三重防護機制
  • 安全過濾:自動排除簽名參數(shù)參與驗簽計算
  • 編碼兼容:自動處理URL特殊字符編碼問題

核心實現(xiàn)解析

1. 主校驗流程

public boolean verifySignature(HttpServletRequest request, 
                              HttpServletResponse response,
                              GridAccountUser accountUser) {
    // 獲取公鑰配置
    StateGridAccount gridAccount = stateGridService
        .getStateGridAccountById(accountUser.getAccountId());
    
    // 請求類型路由
    if(HttpMethod.POST.matches(request.getMethod())) {
        // 處理JSON/Form-Data類型
    } else if(HttpMethod.GET.matches(request.getMethod())) {
        // 處理GET參數(shù)
    }
    
    // 統(tǒng)一返回校驗結(jié)果
}

2. 關(guān)鍵技術(shù)點

2.1 時間戳驗證

private Boolean verifyTimestamp(String timestampStr) {
    long timestamp = Long.parseLong(timestampStr);
    long currentTime = System.currentTimeMillis();
    return Math.abs(currentTime - timestamp) <= 300_000; // 5分鐘有效期
}
  • 防止重放攻擊
  • 要求客戶端服務(wù)端時間同步
  • 誤差窗口可配置化建議

2.2 請求體處理

JSON請求處理:

String requestStr = getRequestBody(request);
JSONObject jsonObject = JSON.parseObject(requestStr);
map.remove("sign"); // 過濾簽名參數(shù)

Form-Data處理:

Map<String, Object> formData = WebUtils.getParametersStartingWith(request, "");
formData.remove("sign");

GET請求處理:

Map<String, String[]> queryParams = request.getParameterMap();
signature = signature.replaceAll(" ", "+"); // 處理URL編碼

2.3 簽名驗證

SignUtil.verifySignature(
    uri,                  // 請求路徑
    data.toString(),      // 過濾后的參數(shù)
    Long.parseLong(timestamp), 
    signature,
    publicKey
);

優(yōu)化建議

1.參數(shù)序列化優(yōu)化

  • 當前同時使用Fastjson和Hutool的JSONUtil,建議統(tǒng)一JSON處理庫
  • 推薦使用Jackson進行標準化處理

2.異常處理增強

try {
    // 驗簽邏輯
} catch (NumberFormatException e) {
    log.error("時間戳格式異常: {}", timestampStr);
    throw new InvalidTimestampException();
} catch (SignatureException e) {
    log.warn("簽名驗證失敗: {}", e.getMessage());
}

3.性能優(yōu)化

  • 添加公鑰緩存機制(RedisCache)
  • 采用連接池管理數(shù)據(jù)庫查詢

4.安全增強

  • 添加重放攻擊計數(shù)器
  • 支持動態(tài)時間窗口配置
  • 增加黑名單IP機制

注意事項

  • 時間同步:確保NTP服務(wù)的時間同步
  • 密鑰管理:建議采用密鑰輪換機制
  • 空參數(shù)處理:需要明確空字符串和null的處理策略
  • 編碼一致性:統(tǒng)一使用UTF-8字符集
  • 日志脫敏:敏感參數(shù)需要做日志過濾

總結(jié)

該實現(xiàn)方案為API接口安全提供了基礎(chǔ)保障,在實際生產(chǎn)環(huán)境中可根據(jù)業(yè)務(wù)需求擴展以下功能:

  • 增加流量限頻控制
  • 實現(xiàn)雙向證書驗證
  • 支持多種哈希算法
  • 添加OpenAPI規(guī)范支持
  • 集成API管理平臺

通過持續(xù)優(yōu)化驗簽流程和完善監(jiān)控機制,可以有效構(gòu)建安全可靠的API網(wǎng)關(guān)體系。

完整代碼

生產(chǎn)秘鑰私鑰工具類

package com.aspire.datasynchron.common.utils;

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Map;


public class KeyGenExample {

    private static final String ALGORITHM = "RSA";

    public static Map<String, String> generateKey() throws NoSuchAlgorithmException {
        // 1. 選擇算法(RSA/EC/DSA)
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance(ALGORITHM);
        keyGen.initialize(2048); // 密鑰長度

        // 2. 生成密鑰對
        KeyPair keyPair = keyGen.generateKeyPair();

        // 3. 獲取公私鑰(Base64 編碼打?。?
        byte[] privateKeyBytes = keyPair.getPrivate().getEncoded();
        byte[] publicKeyBytes = keyPair.getPublic().getEncoded();

        String privateKey = Base64.getEncoder().encodeToString(privateKeyBytes);
        String publicKey = Base64.getEncoder().encodeToString(publicKeyBytes);
        Map<String, String> map = ApiKeyGenerator.generateApiCredentials();
        map.put("private_key", privateKey);
        map.put("public_key", publicKey);
        return map;
    }

    public static void main(String[] args) {
        try {
            Map<String, String> stringStringMap = generateKey();
            System.out.println(stringStringMap);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }
}

生成簽名和驗簽方法

package com.aspire.datasynchron.common.utils;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import org.apache.commons.lang3.ArrayUtils;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/**
 * <b>System:</b>NCC

 * <b>Title:</b>SignUtil.java

 * <b>Description:</b>添加描述信息

 * <b>@author: </b>zhouxiaomin_a

 * <b>@date:</b>2018/6/21 17:00

 * <b>@version:</b> 1.0.0.0

 * <b>Copyright (c) 2017 ASPire Tech.</b>
 */
public class SignUtil {

    private static final String CHARSET = "UTF-8";
    private static final String SIGNATURE_ALGORITHM = "SHA256withRSA";
    private static final String KEY_ALGORITHM = "RSA";

    // 通過傳入私鑰、數(shù)據(jù)和時間戳生成簽名的方法
    public static String generateSignature(String url, String data, long timestamp, String privateKeyStr) throws Exception {
        // 將數(shù)據(jù)和時間戳合并成一個字符串
        String dataWithTimestamp = url + "|" + data + "|" + timestamp;

        // 通過傳入的私鑰字符串生成私鑰
        PrivateKey privateKey = getPrivateKeyFromString(privateKeyStr);

        // 創(chuàng)建簽名對象,使用 SHA256withRSA 算法
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(privateKey);

        // 更新數(shù)據(jù)
        signature.update(dataWithTimestamp.getBytes(StandardCharsets.UTF_8));

        // 生成簽名
        byte[] signedData = signature.sign();

        // 將簽名轉(zhuǎn)換為 Base64 編碼的字符串
        return Base64.getEncoder().encodeToString(signedData);
    }

    // 通過傳入私鑰字符串,生成私鑰對象的方法
    public static PrivateKey getPrivateKeyFromString(String privateKeyStr) throws Exception {
        // 將 Base64 編碼的私鑰字符串解碼為字節(jié)數(shù)組
        byte[] decodedKey = Base64.getDecoder().decode(privateKeyStr);

        // 使用 KeyFactory 生成私鑰對象
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodedKey);

        return keyFactory.generatePrivate(keySpec);
    }

    // 驗證簽名的方法
    public static boolean verifySignature(String url, String data, Long timestamp, String signatureStr, String publicKeyStr) throws Exception {
        if (StringUtils.isEmpty(url) || StringUtils.isEmpty(data) || null == timestamp
                || StringUtils.isEmpty(signatureStr) || StringUtils.isEmpty(publicKeyStr)) {
            return false;
        }
        // 將數(shù)據(jù)和時間戳合并成一個字符串
        String dataWithTimestamp = url + "|" + data + "|" + timestamp;

        // 通過傳入的公鑰字符串生成公鑰
        PublicKey publicKey = getPublicKeyFromString(publicKeyStr);

        // 創(chuàng)建簽名對象,使用 SHA256withRSA 算法
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initVerify(publicKey);

        // 更新數(shù)據(jù)
        signature.update(dataWithTimestamp.getBytes(StandardCharsets.UTF_8));

        // 將 Base64 編碼的簽名字符串轉(zhuǎn)換為字節(jié)數(shù)組
        byte[] signatureBytes = Base64.getDecoder().decode(signatureStr);

        // 驗證簽名
        return signature.verify(signatureBytes);
    }

    // 通過傳入公鑰字符串,生成公鑰對象的方法
    public static PublicKey getPublicKeyFromString(String publicKeyStr) throws Exception {
        // 將 Base64 編碼的公鑰字符串解碼為字節(jié)數(shù)組
        byte[] decodedKey = Base64.getDecoder().decode(publicKeyStr);

        // 使用 KeyFactory 生成公鑰對象
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey);

        return keyFactory.generatePublic(keySpec);
    }

    // 測試代碼
    public static void main(String[] args) throws Exception {

        // 獲取公鑰和私鑰的 Base64 編碼字符串
        String privateKeyStr = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC+3ZTH/VCeWaesY4muy7fOvqLLTX07QpfJVeG1KZKSCjeciih3VRQfMn1PsxL0elMUFIfRKGOtjS7o0+V3UqAwaJCozyxEMPw3OGKQ0bb2dCId/TCnjWkFpSOj1UKct/LdOT/CZ07Bu+8DCynjzHSxwATe2DYWZp8fHf9FAuYjPuXhkeFEkf+/TG5ObyDE4VqzHiTb4XmjkJCuhk98H5CLOCrWb+NiyHpbp/fPF865QzEG1n9/pyFKyMDsBgSxmx0iXDheR6ue/wotxnDvJgGqaG00kD88r/oU2M3xo581a9sF+v6fzNCldtF+MHJJVd4OhFcscahBySEhIUY9TZo/AgMBAAECggEAIh6TP7MBa+VEC5WZocUqHQvIJ0a5adQMNUIkgJGncXLhIRszg62SVMdeTlaJP2n0mwTWiKXLN9Wiup1SimObXjv7DCpI1AHbvHVYbWIH7oOxK6I8xd8KFKfCOMHhUAm0ISbgRnzYP9q8LdObj+zXOYVFeZ62AIgkzte6b9hGUqtWv4yGL3VTiki5TvzHpRPJoeEYHEk+zGhdCn9dr7GY+3mm3EfnNL69s78jWAdkib8fHQsgunOB4NiA4Gnn58Aphzw/SYio6mS5ieRXz4h9ng77UI4agkuU6QhYMdt+s+7YTs4Z6+iXnE3f0zHZJT/UA1GItcxnYuznl2X+vKWS3QKBgQD3L/lUfh5R2N40rB16cE4W75betT59TIjEW+/g5VY4WhZZXEmIi7HWcxoAYXeTp1/Ls2KrKWyAs5ys89lTmasJh2M8afS04mUTCtOO2/bsnUXc0g7P8M913X2fWME+uIVLXBbG2+0xfXGgLCtsgZro5IkDqrHO09SX8s02jOAbJQKBgQDFq5HkGsxJZzS7anFoaBnXxUK590bkIt4eIyOs5Z7AldppWIaT5uCR9TAq3N29rvxBPBwiRKIsghleTHtkvccImDECu6ztVubn1oaudvNnHPbUyi5rfxg+dAKUoLxX3nzniSYupyN94QDq+q/OPiTBopyAXxRmNfn8x3YGvOi0kwKBgQCv3D/E7x1fGa2tR66JR5EnHDn4JHZa6rJ7EPWuyTr4SI+R7+iY7toNOkKLdsx+DhxHbk6Ke6QoRKD5I1vA8JkQ5HOjrbZdYpyKWa99+dzJJnNn0UKcijTvJC+VyK1jlB+xJ8lEnX85MIhAbmxOfD7b5ovcQfrSrT6ZBDMf1kYyyQKBgHQq32NRyGr/B0N5S8rTGxTubceCphvezfCiMA4lKAYAS0qL5xM2pRXCJZubD4mxM7hWziXpdfF4R9ZeVkofKcBISM1VZExbPPpU3fPcHjGkGP93Do7IM4RIg1e7mtR9AaTEujbCrR4GRJbT2sv3Q3y0xwq+Veu3nwHKaveMv6mXAoGBAM0trI9b/k7oHS8z9FfETTeiXxac3puumRcGt3HmCISPmXxc4RWMVbMPUWSzm2KFdWtKEYMMxvSZcEG90rxM/Mh3Uhdj8Pdz2iwAnCghpwzAtp60N2yKxJyq80gRFywTlNp70VxDxYCFZ9Dugjzg7NT2JbhOdSjoZDP9FXg+konq";
        String publicKeyStr = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvt2Ux/1QnlmnrGOJrsu3zr6iy019O0KXyVXhtSmSkgo3nIood1UUHzJ9T7MS9HpTFBSH0ShjrY0u6NPld1KgMGiQqM8sRDD8NzhikNG29nQiHf0wp41pBaUjo9VCnLfy3Tk/wmdOwbvvAwsp48x0scAE3tg2FmafHx3/RQLmIz7l4ZHhRJH/v0xuTm8gxOFasx4k2+F5o5CQroZPfB+Qizgq1m/jYsh6W6f3zxfOuUMxBtZ/f6chSsjA7AYEsZsdIlw4Xkernv8KLcZw7yYBqmhtNJA/PK/6FNjN8aOfNWvbBfr+n8zQpXbRfjBySVXeDoRXLHGoQckhISFGPU2aPwIDAQAB";

        String url = "/api/rest/demo/queryAlarmInfo";
        // 要簽名的數(shù)據(jù)和時間戳
        String json = "{\"SPECIALTY\":8,\"NETWORKTYPE\":801,\"VENDORNAME\":\"華為\",\"NETYPE\":\"801\",\"ALARMTITLE\":\"\",\"ORG_EVENT_ID\":\"\"}";


        Map map = JSONUtil.toBean(json, Map.class);
        String data = map.toString();
        System.out.println(data);

        long timestamp = System.currentTimeMillis();  // 當前時間戳
        System.out.println(timestamp);

        // 生成簽名
        String signature = generateSignature(url, data, timestamp, privateKeyStr);
        System.out.println("Generated Signature: " + signature);

        // 驗證簽名
        boolean isVerified = SignUtil.verifySignature(url, data, timestamp, signature, publicKeyStr);
        System.out.println("Signature Verified: " + isVerified);

        System.out.println("---------------------------------------------------------");

        String url2 = "/api/rest/demo/getUser";
        Map<String, Object> params = new HashMap<>();
        params.put("idcard", "123456");
        long timestamp1 = System.currentTimeMillis();  // 當前時間戳
        System.out.println(timestamp1);
        String data2 = params.toString();
        System.out.println(data2);
        // 生成簽名
        String signature1 = generateSignature(url2, data2, timestamp1, privateKeyStr);
        System.out.println("Generated Signature1: " + signature1);

        // 驗證簽名
        boolean isVerified1 = SignUtil.verifySignature(url2, data2, timestamp1, signature1, publicKeyStr);
        System.out.println("Signature isVerified1: " + isVerified1);

        System.out.println("---------------------------------------------------------");

        String url3 = "/api/rest/demo/getIdCard";
        Map<String, Object> params1 = new HashMap<>();
        params1.put("name", "李四");
        params1.put("age", "27");
        String data3 = params1.toString();
        System.out.println(data3);

        long timestamp2 = System.currentTimeMillis();  // 當前時間戳
        System.out.println(timestamp2);

        // 生成簽名
        String signature2 = generateSignature(url3, data3, timestamp2, privateKeyStr);
        System.out.println("Generated signature2: " + signature2);

        // 驗證簽名
        boolean isVerified2 = SignUtil.verifySignature(url3, data3, timestamp2, signature2, publicKeyStr);
        System.out.println("Signature isVerified2: " + isVerified2);
    }

}

自定義攔截器

package com.aspire.datasynchron.framework.interceptor;

import com.aspire.datasynchron.common.core.domain.model.GridAccountUser;
import com.aspire.datasynchron.common.utils.StringUtils;
import com.aspire.datasynchron.framework.web.service.TokenService;
import com.aspire.datasynchron.framework.web.service.VerifySignatureService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.charset.StandardCharsets;


@Slf4j
@Component
public class SignatureInterceptor implements HandlerInterceptor {
    private final TokenService tokenService;
    private final VerifySignatureService verifySignatureService;

    @Autowired
    public SignatureInterceptor(TokenService tokenService, VerifySignatureService verifySignatureService) {
        this.tokenService = tokenService;
        this.verifySignatureService = verifySignatureService;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String clientType = request.getHeader("clientType");
        if (StringUtils.isNotEmpty(clientType)) {
            GridAccountUser accountUser = tokenService.getAccountUser(request);
            // 自定義驗簽邏輯
            boolean verified = verifySignatureService.verifySignature(request, response, accountUser);
            if (!verified) {
                log.error("驗簽失敗");
                response.setStatus(HttpStatus.FORBIDDEN.value());
                response.setContentType(MediaType.APPLICATION_JSON_VALUE);
                response.setCharacterEncoding(StandardCharsets.UTF_8.name());
                // 構(gòu)建錯誤響應(yīng)
                String errorMessage = "{\"error\": \"簽名不合法\", \"message\": \"Signature is invalid.\"}";
                response.getWriter().write(errorMessage);
                return false;
            }
        }
        return true;
    }
}

驗簽實現(xiàn)類

package com.aspire.datasynchron.framework.web.service;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.aspire.datasynchron.common.core.domain.model.GridAccountUser;
import com.aspire.datasynchron.common.core.redis.RedisCache;
import com.aspire.datasynchron.common.utils.SignUtil;
import com.aspire.datasynchron.stateGrid.domain.StateGridAccount;
import com.aspire.datasynchron.stateGrid.domain.vo.StateGridAccountDetailsVO;
import com.aspire.datasynchron.stateGrid.service.IStateGridAccountService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import org.springframework.web.util.WebUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.*;


@Slf4j
@Service
public class VerifySignatureService {

    @Autowired
    private IStateGridAccountService stateGridService;

    public boolean verifySignature(HttpServletRequest request, HttpServletResponse response, GridAccountUser accountUser) {
        //查詢公鑰
        StateGridAccount gridAccount = stateGridService.getStateGridAccountById(accountUser.getAccountId());
        if (gridAccount == null || StringUtils.isEmpty(gridAccount.getPublicKey())) {
            log.error("賬號[{}]公鑰未配置", accountUser.getAccountId());
            return false;
        }
        String publicKey = gridAccount.getPublicKey();
        String uri = request.getRequestURI();
        // 判斷當前請求方式
        if (HttpMethod.POST.name().equals(request.getMethod())) {
            // 判斷是否是 JSON 格式的請求
            if (MediaType.APPLICATION_JSON_VALUE.equals(request.getContentType())) {
                // 獲取請求體的內(nèi)容
                String requestStr = getRequestBody(request);
                log.info("請求體內(nèi)容:{}", requestStr);
                if (StringUtils.isEmpty(requestStr)) {
                    return false;
                }
                JSONObject jsonObject = JSON.parseObject(requestStr);
                Map map = JSONUtil.toBean(requestStr, Map.class);
                map.remove("sign");
                map.remove("timestamp");
                String timestamp = jsonObject.getString("timestamp");
                String signature = jsonObject.getString("sign");
                // 驗證時間戳
                Boolean verifed = verifTimestamp(timestamp);
                if (!verifed) {
                    return false;
                }
                try {
                    boolean isValid = SignUtil.verifySignature(uri, map.toString(), Long.parseLong(timestamp), signature, publicKey);
                    return isValid;
                } catch (Exception e) {
                    log.error(e.getMessage());
                    return false;
                }


            } else if (request.getContentType() != null && request.getContentType().startsWith(MediaType.MULTIPART_FORM_DATA_VALUE)) {
                // 處理 form 表單數(shù)據(jù)格式
                Map<String, Object> formData = WebUtils.getParametersStartingWith(request, "");
                log.info("表單數(shù)據(jù):{}", formData);
                String timestamp = (String) formData.get("timestamp");
                String signature = (String) formData.get("sign");
                formData.remove("sign");
                formData.remove("timestamp");
                // 驗證時間戳
                Boolean verifed = verifTimestamp(timestamp);
                if (!verifed) {
                    return false;
                }
                try {
                    boolean isValid = SignUtil.verifySignature(uri, formData.toString(), Long.parseLong(timestamp), signature, publicKey);
                    return isValid;
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        } else if (HttpMethod.GET.name().equals(request.getMethod())) {
            // GET 請求的處理,獲取查詢參數(shù)進行驗簽
            Map<String, String[]> queryParams = request.getParameterMap();
            if (queryParams == null) {
                return false;
            }
            Map<String, String> filteredParams = new HashMap<>();
            queryParams.forEach((key, values) -> {
                // 過濾掉 "sign" 和 "timestamp" 參數(shù)
                if (!"sign".equals(key) && !"timestamp".equals(key)) {
                    filteredParams.put(key, values.length > 0 ? values[0] : "");
                }
            });

            String timestamp = request.getParameter("timestamp");
            String signature = request.getParameter("sign");

            if (timestamp == null || signature == null) {
                return false;
            }
            // 驗證時間戳
            Boolean verifed = verifTimestamp(timestamp);
            if (!verifed) {
                return false;
            }
            //+ 符號通常會被轉(zhuǎn)換為一個空格 (%20),這是因為在 URL 編碼中,+ 符號表示空格
            signature = signature.replaceAll(" ", "+");

            boolean isValid = false;
            try {
                isValid = SignUtil.verifySignature(uri, filteredParams.toString(), Long.parseLong(timestamp), signature, publicKey);
                if (!isValid) {
                    return false;  // 返回 false 表示驗簽失敗
                }
                return true;  // 返回 true 表示驗簽成功
            } catch (Exception e) {
                log.error(e.getMessage());
                return false;
            }
        }
        return false;  // 默認返回 false,如果請求方法不支持
    }

    /**
     * @throws
     * @MethodName verifTimestamp
     * @author zhouzihao
     * @param: timestampStr
     * @DateTime 2025年3月25日, 0025 下午 06:13
     * @return: java.lang.Boolean
     * @description:檢查時間戳:確保客戶端和服務(wù)端時間同步,誤差在5分鐘內(nèi)。
     */
    private Boolean verifTimestamp(String timestampStr) {
        long timestamp = Long.parseLong(timestampStr);
        long currentTime = System.currentTimeMillis();
        if (Math.abs(currentTime - timestamp) > 300000) { // 5分鐘
            log.error("驗簽失?。簳r間戳已過期");
            return false;
        }
        return true;
    }

    /**
     * 讀取請求體的內(nèi)容
     */
    private static String getRequestBody(HttpServletRequest request) {
        InputStream in = null;
        StringBuffer sb = null;
        try {
            in = request.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(in,
                    Charset.forName("UTF-8")));
            sb = new StringBuffer("");
            String temp;
            while ((temp = br.readLine()) != null) {
                sb.append(temp);
            }
            if (in != null) {
                in.close();
            }
            if (br != null) {
                br.close();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return sb.toString();
    }
}

到此這篇關(guān)于基于SpringBoot實現(xiàn)HTTP請求簽名驗證機制的文章就介紹到這了,更多相關(guān)SpringBoot HTTP請求簽名驗證內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java代碼里如何拼接SQL語句到mybatis的xml

    Java代碼里如何拼接SQL語句到mybatis的xml

    這篇文章主要介紹了Java代碼里拼接SQL語句到mybatis的xml操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • Mybatis plus枚舉處理器的具體使用

    Mybatis plus枚舉處理器的具體使用

    在開發(fā)中,數(shù)據(jù)庫表中的字段很常見會使用枚舉類型來表示一些固定的取值范圍,本文主要介紹了Mybatis plus枚舉處理器的具體使用,具有一定的參考價值,感興趣的可以了解一下
    2024-03-03
  • Springboot下RedisTemplate的兩種序列化方式實例詳解

    Springboot下RedisTemplate的兩種序列化方式實例詳解

    這篇文章主要介紹了Springboot下RedisTemplate的兩種序列化方式,通過定義一個配置類,自定義RedisTemplate的序列化方式,結(jié)合實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-09-09
  • 如何在Java中使用標準庫創(chuàng)建臨時文件

    如何在Java中使用標準庫創(chuàng)建臨時文件

    有時候我們程序運行時需要產(chǎn)生中間文件,但是這些文件只是臨時用途,并不做長久保存,我們可以使用臨時文件,不需要長久保存,這篇文章主要給大家介紹了關(guān)于如何在Java中使用標準庫創(chuàng)建臨時文件的相關(guān)資料,需要的朋友可以參考下
    2023-10-10
  • Spring Security 中如何讓上級擁有下級的所有權(quán)限(案例分析)

    Spring Security 中如何讓上級擁有下級的所有權(quán)限(案例分析)

    這篇文章主要介紹了Spring Security 中如何讓上級擁有下級的所有權(quán)限,本文通過案例分析給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-09-09
  • Springboot項目啟動優(yōu)化方式

    Springboot項目啟動優(yōu)化方式

    文章詳細介紹了Spring Boot項目的啟動優(yōu)化策略,包括懶加載、異步初始化、精簡依賴、JVM優(yōu)化和使用Actuator監(jiān)控等方法,旨在提高項目的啟動速度和運行性能
    2025-03-03
  • java 分轉(zhuǎn)元與元轉(zhuǎn)分實現(xiàn)操作

    java 分轉(zhuǎn)元與元轉(zhuǎn)分實現(xiàn)操作

    這篇文章主要介紹了java 分轉(zhuǎn)元與元轉(zhuǎn)分實現(xiàn)操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • spring boot Rabbit高級教程(最新推薦)

    spring boot Rabbit高級教程(最新推薦)

    RabbitMQ的消息過期是基于追溯方式來實現(xiàn)的,也就是說當一個消息的TTL到期以后不一定會被移除或投遞到死信交換機,而是在消息恰好處于隊首時才會被處理,本篇文章給大家介紹spring boot Rabbit高級教程,感興趣的朋友一起看看吧
    2023-10-10
  • SpringBoot3整合SpringCloud啟動后nacos報錯獲取不到配置、無法注冊服務(wù)的解決方案

    SpringBoot3整合SpringCloud啟動后nacos報錯獲取不到配置、無法注冊服務(wù)的解決方案

    文章介紹了如何使用Spring Boot 3.3.4和Spring Cloud 2023.0.3搭建微服務(wù)項目,并解決與Nacos服務(wù)注冊發(fā)現(xiàn)和配置中心的集成問題,主要解決了依賴版本不兼容、配置文件導(dǎo)入問題及服務(wù)注冊失敗等問題,感興趣的朋友跟隨小編一起看看吧
    2025-02-02
  • Java建造者模式構(gòu)建復(fù)雜對象的最佳實踐

    Java建造者模式構(gòu)建復(fù)雜對象的最佳實踐

    建造者模式,是一種對象構(gòu)建模式?它可以將復(fù)雜對象的建造過程抽象出來,使這個抽象過程的不同實現(xiàn)方法可以構(gòu)造出不同表現(xiàn)的對象。本文將通過示例講解建造者模式,需要的可以參考一下
    2023-04-04

最新評論