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

Spring?Boot使用HMAC-SHA256對訪問密鑰加解密

 更新時間:2024年12月26日 08:34:05   作者:憤怒的代碼  
本文主要介紹了使用HMAC-SHA256算法進行客戶端和服務(wù)端之間的簽名驗簽,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

一、客戶端示例

假設(shè)這是一個Java客戶端(可能是后端服務(wù)或桌面應(yīng)用等),要調(diào)用你的服務(wù)接口 /api/secure,并用 HMAC-SHA256 做簽名。

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Base64;

public class HmacClientExample {

    public static void main(String[] args) throws Exception {
        // 1) 準備必要參數(shù)
        String accessKeyId = "myKeyId";
        String accessKeySecret = "myKeySecret"; // 保密
        String method = "POST";
        String path = "/api/secure";
        // 例如攜帶一個 timestamp (yyyyMMddHHmmss)
        String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));

        // 2) 如果有請求體,需要計算 bodyHash (這里只是示例)
        //   實際可對 JSON 字符串做 MD5 或 SHA256,再 Hex 或 Base64
        String requestBody = "{\"foo\":\"bar\"}"; // JSON
        String bodyHash = sha256Hex(requestBody);

        // 3) 拼裝 StringToSign (示例邏輯,可自定義)
        //    這里用換行分隔 method, path, timestamp, bodyHash
        String stringToSign = method + "\n" 
                              + path + "\n" 
                              + timestamp + "\n" 
                              + bodyHash;

        // 4) 做 HMAC-SHA256
        String signature = hmacSha256Base64(stringToSign, accessKeySecret);

        // 5) 將簽名和 keyId、timestamp 放到 HTTP 頭部
        //    偽代碼: 構(gòu)建 HTTP 請求
        System.out.println("X-AccessKeyId: " + accessKeyId);
        System.out.println("X-Timestamp: " + timestamp);
        System.out.println("X-Signature: " + signature);
        // 之后再把 requestBody 當作 JSON 發(fā)出 (POST)
        // ...

        // 這是示例演示,真實項目中可用 HttpClient、OkHttp 等發(fā)請求
    }

    /**
     * 計算字符串的 SHA-256 再轉(zhuǎn) hex (可選:也可用 Base64)
     */
    private static String sha256Hex(String data) throws Exception {
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        byte[] bytes = digest.digest(data.getBytes(StandardCharsets.UTF_8));
        return bytesToHex(bytes);
    }

    /**
     * HMAC-SHA256 + Base64
     */
    private static String hmacSha256Base64(String data, String secret) throws Exception {
        Mac mac = Mac.getInstance("HmacSHA256");
        SecretKeySpec keySpec = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
        mac.init(keySpec);
        byte[] rawHmac = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(rawHmac);
    }

    private static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder(bytes.length * 2);
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }
}
  • 核心StringToSign 拼裝 + HMAC-SHA256 計算簽名 + 在請求頭中帶上 accessKeyId、timestamp、signature。
  • bodyHash 的計算方式可自行定義,也可以用 MD5、直接放明文 body 等。只要客戶端和服務(wù)端保持一致即可。

二、服務(wù)端示例 (Spring Boot)

下面以 Spring Boot + Controller 為例,展示如何驗證簽名。主要邏輯:

  • 從 HTTP 頭中取 X-AccessKeyIdX-TimestampX-Signature。
  • 根據(jù) accessKeyId 找到 secret;
  • 用相同的方式拼裝 StringToSign
  • 做同樣的 HMAC-SHA256 計算;
  • 比對與客戶端傳來的 signature 是否相同。

2.1 Controller 示例

@RestController
@RequestMapping("/api")
public class SecureApiController {

    // 示例:內(nèi)存中保存 keyId -> keySecret 映射
    private Map<String, String> keyStore = new HashMap<>();

    public SecureApiController() {
        // 假設(shè)這里初始化了一個myKeyId -> myKeySecret
        keyStore.put("myKeyId", "myKeySecret");
    }

    @PostMapping("/secure")
    public ResponseEntity<?> secureEndpoint(
            HttpServletRequest request,
            @RequestBody(required=false) String body // raw JSON
    ) {
        try {
            // 1) 從header讀取
            String accessKeyId = request.getHeader("X-AccessKeyId");
            String timestamp = request.getHeader("X-Timestamp");
            String clientSignature = request.getHeader("X-Signature");

            if (accessKeyId == null || timestamp == null || clientSignature == null) {
                return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Missing auth headers");
            }

            // 2) 查找keySecret
            String keySecret = keyStore.get(accessKeyId);
            if (keySecret == null) {
                return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid accessKeyId");
            }

            // 3) 計算 bodyHash(可選)
            //    假設(shè)客戶端用了 sha256Hex(body)
            String bodyHash = sha256Hex(body == null ? "" : body);

            // 4) 與客戶端相同的拼接方式
            String method = request.getMethod(); // "POST"
            String path = request.getRequestURI(); // "/api/secure"
            // StringToSign
            String stringToSign = method + "\n" 
                                + path + "\n" 
                                + timestamp + "\n" 
                                + bodyHash;

            // 5) 服務(wù)端做 HMAC-SHA256
            String serverSignature = hmacSha256Base64(stringToSign, keySecret);

            // 6) 比對簽名
            if (!serverSignature.equals(clientSignature)) {
                return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Signature mismatch");
            }

            // 7) 可選校驗: timestamp 是否過期
            if (!checkTimestampValid(timestamp)) {
                return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Timestamp expired or invalid");
            }

            // 8) 一切正常
            return ResponseEntity.ok("Success! Request body was: " + body);

        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Auth error: " + e.getMessage());
        }
    }

    // 計算 SHA256Hex
    private String sha256Hex(String data) throws Exception {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] digest = md.digest(data.getBytes(StandardCharsets.UTF_8));
        return bytesToHex(digest);
    }

    // HMAC-SHA256 + Base64
    private String hmacSha256Base64(String data, String secret) throws Exception {
        Mac mac = Mac.getInstance("HmacSHA256");
        SecretKeySpec keySpec = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
        mac.init(keySpec);
        byte[] rawHmac = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(rawHmac);
    }

    private String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder(bytes.length * 2);
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }

    // 時間戳校驗 (±15分鐘示例)
    private boolean checkTimestampValid(String timestampStr) {
        try {
            // 這里假設(shè) timestampStr 是 yyyyMMddHHmmss
            DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
            LocalDateTime reqTime = LocalDateTime.parse(timestampStr, fmt);
            LocalDateTime now = LocalDateTime.now();
            return !reqTime.isBefore(now.minusMinutes(15)) && !reqTime.isAfter(now.plusMinutes(15));
        } catch (Exception e) {
            return false;
        }
    }
}
  • 注意:上面為了演示方便,用 @RequestBody(required=false) String body 直接拿到原始 JSON 字符串,再做 sha256Hex;如果是對象映射,你要注意讀取流計算摘要的先后順序。
  • 你也可以在 Filter 或 Interceptor 里做這個簽名驗簽邏輯,避免在每個 Controller 里寫。
  • timestamp 校驗 + 可能的 nonce 防重放(可用 Redis 記錄 5 分鐘內(nèi)出現(xiàn)過的 (accessKeyId,timestamp,nonce)),以更好地防御重復(fù)調(diào)用。

三、總結(jié)

  • 客戶端
    • 準備 accessKeyIdaccessKeySecret;
    • 拼出 StringToSign(通常包含 method、path、timestamp、bodyHash 等);
    • HMAC-SHA256( StringToSignaccessKeySecret ) → signature;
    • 在 HTTP 請求頭里帶上 accessKeyIdsignaturetimestamp
    • 用 JSON 作為請求體時,別忘了和服務(wù)端在 bodyHash 算法上保持一致。
  • 服務(wù)端
    • 通過 accessKeyId 找到對應(yīng)的 accessKeySecret
    • 按同樣規(guī)則構(gòu)造 StringToSign;
    • 計算 HMAC-SHA256 并和客戶端的 signature 對比;
    • 一致則通過,不一致則 401/403;
    • 可加時間戳、nonce、限流 等加強安全性。
  • 優(yōu)點
    • 不需要公鑰/私鑰,也不需要RSA 加解密;
    • 計算速度快、實現(xiàn)相對簡單;
    • 通用性強,許多云廠商、API網(wǎng)關(guān)都采用類似 HMAC 簽名模式。
  • 注意
    • 一定要保護好 accessKeySecret,客戶端泄露就會被冒用。
    • 使用 HTTPS 來保證傳輸安全,防止中間人截獲簽名或篡改。
    • 若對大文件、流式上傳等,需要在數(shù)據(jù)處理上稍作適配(hash可能需分段計算)。

這套 HMAC-SHA256 簽名鑒權(quán)就是在很多云服務(wù)(阿里云、AWS、騰訊云)都在用的模式。只要客戶端與服務(wù)端約定好StringToSign 的拼裝方式、accessKeyId → secret 映射、時間戳/nonce防重放,就能形成一套輕量、高效的對外接口鑒權(quán)機制。

到此這篇關(guān)于Spring Boot使用HMAC-SHA256對訪問密鑰加解密的文章就介紹到這了,更多相關(guān)SpringBoot 訪問密鑰加解密內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java實現(xiàn)銀行存取款

    Java實現(xiàn)銀行存取款

    這篇文章主要為大家詳細介紹了Java實現(xiàn)銀行存取款,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • Java基礎(chǔ)詳解之內(nèi)存泄漏

    Java基礎(chǔ)詳解之內(nèi)存泄漏

    這篇文章主要介紹了Java基礎(chǔ)詳解之內(nèi)存泄漏,文中有非常詳細的代碼示例,對正在學(xué)習(xí)java的小伙伴們有很好地幫助,需要的朋友可以參考下
    2021-04-04
  • Java利用Spire.Doc for Java實現(xiàn)在Word中插入分頁符與分節(jié)符

    Java利用Spire.Doc for Java實現(xiàn)在Word中插入分頁符與分節(jié)符

    在使用 Java 進行 Word 文檔自動化生成的過程中,對文檔布局的精細控制往往是開發(fā)者面臨的實際需求,本文將介紹如何利用 Spire.Doc for Java 庫,通過 Java 代碼在 Word 文檔中插入分頁符和分節(jié)符,感興趣的小伙伴可以參考下
    2026-05-05
  • Java 8 Lambda 表達式比較器使用示例代碼

    Java 8 Lambda 表達式比較器使用示例代碼

    這篇文章主要介紹了Java 8 Lambda 表達式比較器使用示例代碼,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-08-08
  • java多線程編程之Synchronized塊同步方法

    java多線程編程之Synchronized塊同步方法

    這篇文章主要介紹了java多線程編程之Synchronized塊同步方法,synchronized關(guān)鍵字又稱同步鎖,當方法執(zhí)行完后,會自動釋放鎖鎖,只有一個線程能進入此方法,看看下文中各種例子對synchronized的詳細解釋
    2015-12-12
  • Spring Boot接口設(shè)計防篡改、防重放攻擊詳解

    Spring Boot接口設(shè)計防篡改、防重放攻擊詳解

    這篇文章主要給大家介紹了關(guān)于Spring Boot接口設(shè)計防篡改、防重放攻擊的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學(xué)習(xí)或者使用Spring Boot具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • Java生成獨一無二的工單號實例

    Java生成獨一無二的工單號實例

    這篇文章主要介紹了Java生成獨一無二的工單號實例,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-09-09
  • SpringBoot整合Springsecurity實現(xiàn)數(shù)據(jù)庫登錄及權(quán)限控制功能

    SpringBoot整合Springsecurity實現(xiàn)數(shù)據(jù)庫登錄及權(quán)限控制功能

    本教程詳細介紹了如何使用SpringBoot整合SpringSecurity實現(xiàn)數(shù)據(jù)庫登錄和權(quán)限控制,本文分步驟結(jié)合實例代碼給大家介紹的非常詳細,感興趣的朋友跟隨小編一起看看吧
    2024-10-10
  • IDEA的.idea文件夾和iml文件使用方式

    IDEA的.idea文件夾和iml文件使用方式

    這篇文章主要介紹了IDEA的.idea文件夾和iml文件使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • SpringCloud中的@FeignClient注解使用詳解

    SpringCloud中的@FeignClient注解使用詳解

    在Spring Cloud中使用Feign進行服務(wù)間的調(diào)用時,通常會使用@FeignClient注解來標記Feign客戶端接口,這篇文章給大家介紹SpringCloud中的@FeignClient注解使用詳解,感興趣的朋友一起看看吧
    2025-06-06

最新評論

枣强县| 浙江省| 壤塘县| 历史| 阳江市| 巴东县| 南丹县| 石城县| 延庆县| 宣威市| 壤塘县| 偏关县| 玉林市| 阜城县| 黑水县| 方正县| 三台县| 昌平区| 湘潭县| 吴旗县| 芷江| 怀远县| 东兴市| 云龙县| 峨边| 晋江市| 南充市| 安仁县| 驻马店市| 通州区| 华池县| 英吉沙县| 遵化市| 阆中市| 伊金霍洛旗| 交口县| 拉孜县| 云霄县| 湟源县| 惠安县| 忻城县|