1.5 接入方签名计算准则
签名计算准则
1 签名算法
HMAC
即基于哈希的消息认证码(Hash-based Message Authentication Code),是一种使用密码散列函数,同时结合一个加密密钥,通过特定计算方式生成的消息认证码(MAC)。SHA-256
(Secure Hash Algorithm 256)是散列函数(或哈希函数)的一种,能对一个任意长度的消息,计算出一个32字节长度的字符串(又称消息摘要)。
本系统所有接口的签名算法采用的是HMAC-SHA256
,它是结合了SHA-256
哈希函数和一个密钥的消息认证码算法,用于验证数据的完整性和真实性。
参考:
2 签名参数
以任何方式请求任何接口,必须在URL携带以下三个参数:
access_key
:开发者在开放平台申请的调用凭证包括access_key
和access_token
。其中,access_token
开放平台和开发者约定的签名密钥,而access_key
作为凭证的key,通过该key匹配对应的access_token
。ts
:请求调用行为发生时的时间戳(单位毫秒),该参数必须作为签名算法的一部分(后面示例中会讲到),且该参数具备有效期比如10s内的调用才是有效的调用。sign
:根据ts
、接口约定的签名参数以及access_token
算出的签名摘要。
其他参与签名计算逻辑的参数因API而异,具体可以参考每个API的详细介绍。
3 签名示例
- 假如某接口需要的签名参数如下:
参数 | 数值 | 类型 | 说明 |
---|---|---|---|
app_id | bili123456789 | String | - |
ss_id | 100052 | Number | - |
p_name | bili_user_zhang | String | - |
show_enable | true | Boolean | 布尔类型的参数,一定是小写的true/false |
targets | 102,103,89 | List<Number> | 如果待签名参数是数组、List&Set等类型,则需要将元素通过, 序列化为单一字符串 |
- 调用时时间戳
ts=1736257902605
- 已申请的
access_token=DsI5UxNG5NWuYTJlNDg1NGFkMzRl9Ukp
则结算过程如下:
(1)将每个参数对,拼接为name=value
的结构,「app_id=bili123456789,ss_id=100052,p_name=bili_user_zhang,show_enable=true,targets=102,103,89,ts=1736257902605」
。
任何需要签名的参数,无论何种数据类型,如果该字段缺省,则该参数不参与签名。需要注意的是,空字符串''
和缺省是相同语义的即不参与签名。
(2)将上述参数对按照字典序升序排序,得到排序结果,「app_id=bili123456789,p_name=bili_user_zhang,show_enable=true,ss_id=100052,targets=102,103,89,ts=1736257902605」
。
(3)将上述升序的参数对,通过&
字符拼接,形成完整的待签名的数据,app_id=bili123456789&p_name=bili_user_zhang&show_enable=true&ss_id=100052&targets=102,103,89&ts=1736257902605
。
(4)将access_token=DsI5UxNG5NWuYTJlNDg1NGFkMzRl9Ukp
作为密钥创建基于HMAC-SHA256的算法实例(签名代码参考中会讲到),然后将步骤(3)
中的数据进行散列,经过Base64编码&替换(将URL不友好的字符+/=
替换为B
),最终得到摘要sign=WbGNoWSnhogpKzilnQfPciPYdJgiTc2w6T2BI7Bcpo4B
。
4 签名代码参考
public class SignGenerator {
private static final String ALGORITHM = "HmacSHA256";
public static String sign(List<Pair<String, String>> parameters, String accessToken) throws Exception {
String data = parameters.stream()
.map(p -> String.format("%s=%s", p.getKey(), p.getValue()))
.sorted(Comparator.comparing(Function.identity()))
.collect(Collectors.joining("&"));
Mac mac = Mac.getInstance(ALGORITHM);
mac.init(new SecretKeySpec(accessToken.getBytes(StandardCharsets.UTF_8), ALGORITHM));
byte[] rawHmac = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
String rawSign = Base64.getEncoder().encodeToString(rawHmac);
//将可能导致URL安全隐患的特殊字符(+、/、=)替换为B
return rawSign.replaceAll("[+/=]", "B");
}
}
5 版本变更
版本 | 说明 | 时间 |
---|---|---|
1.0 | 初版签名算法摘要 | 2025-01-08 11:47:00 |