华为云、阿里云、AWS签名机制详解! AK/SK + HMAC-SHA256 签名鉴权!

今天在做机动车重点库是遇到了一个新的鉴权模式,本质上和:

  • 华为云
  • 阿里云
  • AWS

那套签名机制类似。 总体做下来感觉比较有记录意义,现在分享出来给大家做参考。

目录

一、需要做的事情

二、规则

三、示例

四、真正参与签名的数据

[body 要按 key 排序](#body 要按 key 排序)

五、最终签名原文

[六、Java 完整工具类(直接能用)](#六、Java 完整工具类(直接能用))

[Hmac 工具类](#Hmac 工具类)

七、调用示例

请求头

八、最容易踩坑的地方(你一定会遇到)

[1 body字段顺序](#1 body字段顺序)

[2 path 不是完整 URL](#2 path 不是完整 URL)

[3 POST 必须大写](#3 POST 必须大写)

[4 \n 换行问题](#4 \n 换行问题)

[5 body 不是 JSON](#5 body 不是 JSON)

[6 Content-Type](#6 Content-Type)

九、政务系统现状


一、需要做的事情

核心只有三步:

步骤 内容
1 组装签名字符串
2 用 SK 做 HmacSHA256
3 Base64 编码后放 header

二、规则

签名原文格式:

复制代码
HTTP_METHOD
PATH
AK
TIMESTAMP
BODY排序后的字段拼接

注意:

复制代码
是直接拼接
不是 JSON
不是 &
不是 urlencode

三、示例

请求:

复制代码
POST
"****/****/test"

AK:

复制代码
appkey92f6

时间戳:

复制代码
1685443083119

body:

复制代码
{
  "authType":1,
  "lend_time":"2023-05-19 23:00:00",
  "org_code":"51013",
  "org_code_all":"510",
  "pageNo":1,
  "pageSize":5,
  "start_time":"2023-05-19 00:00:00"
}

四、真正参与签名的数据

注意:

body 要按 key 排序

变成:

复制代码
authType1
lend_time2023-05-19 23:00:00
org_code51013
org_code_all510
pageNo1
pageSize5
start_time2023-05-19 00:00:00

五、最终签名原文

复制代码
POST
****/***/test
appkey92f6
1685443083119
authType1
lend_time2023-05-19 23:00:00
org_code51013
org_code_all510
pageNo1
pageSize5
start_time2023-05-19 00:00:00

注意:

文档里的 \n 是换行


六、Java 完整工具类(直接能用)

Hmac 工具类

复制代码
import com.alibaba.fastjson.JSON;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Map;
import java.util.TreeMap;

public class HmacSignUtil {

    /**
     * 生成签名
     */
    public static String sign(
            String method,
            String path,
            String ak,
            String sk,
            String timestamp,
            Map<String, Object> body
    ) throws Exception {

        // 1 body按key排序
        TreeMap<String, Object> sortedMap = new TreeMap<>(body);

        // 2 拼接body
        StringBuilder bodyBuilder = new StringBuilder();

        for (Map.Entry<String, Object> entry : sortedMap.entrySet()) {
            bodyBuilder.append(entry.getKey())
                    .append(entry.getValue());
        }

        // 3 拼接签名原文
        String signStr =
                method.toUpperCase() + "\n"
                        + path + "\n"
                        + ak + "\n"
                        + timestamp + "\n"
                        + bodyBuilder;

        System.out.println("签名原文:");
        System.out.println(signStr);

        // 4 HmacSHA256
        Mac mac = Mac.getInstance("HmacSHA256");

        SecretKeySpec secretKeySpec =
                new SecretKeySpec(sk.getBytes(StandardCharsets.UTF_8),
                        "HmacSHA256");

        mac.init(secretKeySpec);

        byte[] bytes =
                mac.doFinal(signStr.getBytes(StandardCharsets.UTF_8));

        // 5 Base64
        return Base64.getEncoder().encodeToString(bytes);
    }
}

七、调用示例

复制代码
Map<String, Object> body = new HashMap<>();

body.put("authType", 1);
body.put("lend_time", "2023-05-19 23:00:00");
body.put("org_code", "51013");
body.put("org_code_all", "510");
body.put("pageNo", 1);
body.put("pageSize", 5);
body.put("start_time", "2023-05-19 00:00:00");

String ak = "你的AK";
String sk = "你的SK";

String timestamp = String.valueOf(System.currentTimeMillis());

String sign = HmacSignUtil.sign(
        "POST",
        "****/****/test",
        ak,
        sk,
        timestamp,
        body
);

System.out.println(sign);

请求头

然后请求时:

复制代码
headers.add("X-BG-HMAC-SIGNATURE", sign);
headers.add("X-BG-HMAC-ALGORITHM", "HmacSHA256");
headers.add("X-BG-HMAC-ACCESS-KEY", ak);
headers.add("X-BG-DATE-TIME", timestamp);
headers.add("Accept", "*/*");

八、最容易踩坑的地方(你一定会遇到)

1 body字段顺序

必须:

复制代码
按 key 字典序排序

所以:

复制代码
TreeMap

非常关键。


2 path 不是完整 URL

错误:

复制代码
https://xx.com/***/test

正确:

复制代码
"****/****/test"

只取:

复制代码
/*** 后面的内容

3 POST 必须大写

复制代码
POST
GET

4 \n 换行问题

必须:

复制代码
"\n"

不能:

复制代码
System.lineSeparator()

5 body 不是 JSON

很多人会错写:

复制代码
JSON.toJSONString(body)

这是错的。

文档要求:

复制代码
key + value 拼接

6 Content-Type

只有:

复制代码
application/json
application/x-www-form-urlencoded

才参与 body 签名。


九、政务系统现状

鉴权 类型
HMAC 最常见
JWT 常见
OAuth2 平台类
国密 SM2/SM3/SM4 政务高频
RSA 签名 公安常见
相关推荐
To_OC40 分钟前
手写快排次次翻车?别死背快排模板了,这才是面试官想听的底层逻辑
javascript·算法·排序算法
饼干哥哥1 小时前
Reddit VOC调研太慢?搭一个AI专家团队半小时洞察任何品类|以猫用饮水机为例
人工智能·算法·ai编程
地平线开发者3 小时前
Transformer模型部署之性能优化指南
算法
地平线开发者3 小时前
人在途中:从“编译失败”到“模型可落地”——CUDA 自定义算子
算法·自动驾驶
半个落月6 小时前
从递归到快速排序:用 JavaScript 把分治思想讲明白
javascript·算法·面试
小月土星7 小时前
JavaScript 快速排序:从 pivot、双指针到分治思想
javascript·算法·面试
小月土星7 小时前
JavaScript 递归入门:从 1 到 n 求和,再到数组扁平化
javascript·算法·面试
To_OC1 天前
LC 1 两数之和:面试第一道必考题,暴力解法直接被面试官 pass
javascript·算法·leetcode
鱼鱼不愚与1 天前
《原来如此 | 第01期:为什么导航软件能预测红绿灯倒计时?》
算法