一、鉴权认证串authorization
authorization: securityReq authString/signedHeaders/signature
鉴权认证串authorization示例:
RSA算法:
authorization: YOP-RSA2048-SHA256 yop-auth-v3/app_100123456789/2021-12-08T11:59:16Z/1800/content-type;x-yop-appkey;x-yop-content-sha256;x-yop-request-id/pOVoj1mI5bqYQQKTlE8iIYm0DKHpL5Q2vscY03lwP3KXpHRPJlKQfEOgpW-jfsyWf46c-uPehOZfOke7vla3rY6FtAVeoX0g8319WEdvQVgXwzW7xPtp5er4No8gpCrizsbmp2Fw7NSjASGsCaLEEri8iHsvN_TgFsGEIUf9JtQYWkoqdOh6vK1-xZvisp2ePAg2GKHy1Y0tbkXbzO9Bp_dBkgEHI7B2N80mzn-tEZ0xi6uMKSSvI8VPK14Rys8pJ4c4I4RZjoDEnxxsG2Z977RGtCuf_3RvrwohxECO5iF8BMjJF89nqi50QaZtS2mx32649_cORFLbD8VFpQhyxA$SHA256
——————————————————————————————————————————————————————————————————————
SM算法:
authorization: YOP-SM2-SM3 yop-auth-v3/app_100123456789/2021-12-08T11:59:16Z/1800/content-type;x-yop-appkey;x-yop-content-sm3;x-yop-request-id/mLJb2KO9dH0Sb4n2EqZZRIkZut5lgDP-LHZhNZ2j0TggQ6gMzPem4sznJBvzDk0a--K9YfzUjQWZFPyFQUOgmA$SM3
1、安全需求securityReq
YOP支持以下两种安全需求securityReq:
- YOP-RSA2048-SHA256
- YOP-SM2-SM3
2、认证字符串authString
认证字符串authString,由协议版本protocolVersion、应用标识appKey、日期值timestamp和签名有效时长expiredSeconds组成。确保 YOP 平台在收到请求时能使用相同的签名协议并匹配您计算出的签名且在有效期内。否则,您的请求将被拒绝。
a、协议版本protocolVersion,以’/'结尾
目前固定为 yop-auth-v3,以’/'结尾:
yop-auth-v3/
b、应用标识appKey,以’/'结尾
您的 appKey,以’/'结尾如:
app_100123456789/
c、日期值timestamp,以’/'结尾
日期值timestamp 遵循 ISO8601 基本格式,即 YYYY-MM-DDTHH:MM:SSZ,以’/'结尾。该日期值timestamp 必须与您在所有步骤中使用的值保持一致,比如 x-yop-date 标头。
2021-12-08T11:59:16Z/
d、签名有效时长expiredSeconds
无需以’/'结尾如:
1800
3、签名头signedHeaders
签名头signedHeaders 由规范标头canonicalHeaders 中的标头名称列表组成。签名头signedHeaders 的作用是,告知 YOP 平台请求中的哪些标头是签名过程的一部分以及在验证请求时 YOP 平台可以忽略哪些标头(例如,由代理添加的任何附加标头)。
以下是签名头signedHeaders 的伪代码格式。Lowercase 表示将所有字符转换为小写字母的函数。Sort 表示按照标头名称的 ASCII 顺序对所有标头进行升序排序。多个标头名称以’;‘分隔,结尾处不加’;'。
signedHeaders: Sort(Lowercase(HeaderName0);Lowercase(HeaderName1); ... Lowercase(HeaderNameN))
示例:
signedHeaders: content-type;x-yop-appkey;x-yop-content-sha256;x-yop-request-id
4、签名signature
签名signature,由商户私钥isvPrivateKey、规范请求canonicalRequest和签名算法SIGNER生成。其中,SIGNER 一般为SM算法、RSA算法。
签名过程是,商户用摘要算法对规范请求canonicalRequest 生成摘要,然后用自己的私钥对这个摘要进行加密,得到的就是签名signature。伪代码如下:
signature: SIGNER(isvPrivateKey, canonicalRequest)
a、规范请求canonicalRequest
规范请求canonicalRequest,由认证字符串authString、Http请求方法httpRequestMethod、规范URI canonicalURI、规范查询字符串canonicalQueryString和规范标头canonicalHeaders组成。用于生成摘要。
canonicalRequest:
authString + "\n" +
httpRequestMethod + "\n" +
canonicalURI + "\n" +
canonicalQueryString + "\n" +
canonicalHeaders
i、认证字符串authString,以’\n’换行符结尾
见上文,以’\n’换行符结尾,示例:
yop-auth-v3/app_100123456789/2021-12-08T11:59:16Z/1800 + "\n"
ii、Http请求方法httpRequestMethod,以’\n’换行符结尾
Http请求方法httpRequestMethod,分为 POST 和 GET 两种方式。以’\n’换行符结尾,示例:
POST + "\n"
iii、规范URI canonicalURI,以’\n’换行符结尾
规范URI canonicalURI,是 API 的请求路径。以’\n’换行符结尾,示例:
/rest/v2.0/opr/queryorder + "\n"
vi、规范查询字符串canonicalQueryString,以’\n’换行符结尾
针对 GET 、POST 请求且内容类型为 json,规范查询字符串canonicalQueryString 遵循 RFC 3986,构建步骤如下:
- 对每个参数名称key 和参数值value 进行 URI 编码;
- 用’='拼接 URI 编码后的参数名称key 和参数值value。如果参数没有参数值value,value为空字符串。例如:urlencode(key1)=urlencode(value1),urlencode(key2)=urlencode(value2);
- 按照参数名称key 的 ASCII 顺序,对拼接后的参数对进行升序排序Sort。例如,以大写字母 F(ASCII 代码 70,10进制)开头的参数名称key 排在以小写字母 b(ASCII 代码 98,10进制)开头的参数名称key 之前;
- 用’&‘拼接排序后的多个参数对,最后一个参数对后面无需拼接’&'。
注意:
- 如果请求没有查询字符串,则规范查询字符串canonicalQueryString 为空字符串。
- 针对 POST 请求,且内容类型为 form,即application/x-www-form-urlencoded或者multipart/form-data的请求,规范查询字符串canonicalQueryString 一律为空字符串。
规范查询字符串canonicalQueryString 伪代码如下,以’\n’换行符结尾:
Sort(urlencode(key1)=urlencode(value1)&urlencode(key2)=urlencode(value2)&...&urlencode(keyN)=urlencode(valueN)) + "\n"
v、规范标头canonicalHeaders
规范标头canonicalHeaders,由 HTTP 请求头中标头名称和标头值拼接组成。标头必须包含 x-yop-appkey、x-yop-request-id、x-yop-content-sha256。
以下是规范标头canonicalHeaders 的伪代码格式。Lowercase 表示将所有字符转换为小写字母的函数。Trimall 表示删除前后的多余空格并将连续空格转换为单个空格。Sort 表示按照标头名称的 ASCII 顺序对所有标头进行升序排序。标头名称和标头值以’:‘拼接,每个标头后面拼接’\n’,最后一个标头后面无需拼接’\n’。
Sort(Lowercase(HeaderName0) + ":" + Trimall(HeaderValue0) + "\n" +
Lowercase(HeaderName1) + ":" + Trimall(HeaderValue1) + "\n" +
...
Lowercase(HeaderNameN) + ":" + Trimall(HeaderValueN))
其中,x-yop-content-sha256 由请求参数组成,构建步骤如下:
- 构建请求参数字符串A
针对 GET 请求,请求参数字符串A 为空字符串。
针对 POST 请求,且内容类型为 json,请求参数字符串A 为 json 字符串。
对于 POST 请求,且内容类型为 form,规则如下:
a. 拼接非文件类型的参数键值对,对每个参数名称key 和参数值value 进行 URI 编码;
b. 用’=‘拼接 URI 编码后的参数名称key 和参数值value。如果参数没有参数值value,value为空字符串。例如:urlencode(key1)=urlencode(value1),urlencode(key2)=urlencode(value2);
c. 按照参数名称key 的 ASCII 顺序,对拼接后的参数对进行升序排序Sort。例如,以大写字母 F(ASCII 代码 70,10进制)开头的参数名称key 排在以小写字母 b(ASCII 代码 98,10进制)开头的参数名称key 之前;
d. 用’&‘拼接排序后的多个参数对,最后一个参数对后面无需拼接’&'。 - 用 sha256 算法对请求参数字符串A 计算摘要,并转为 hex 值。伪代码为hex(sha256(A))
b、计算签名
计算签名的具体步骤如下,以 YOP-RSA2048-SHA256 为例:
- 将规范请求canonicalRequest 转换为字节数组byte[];
- 使用 java.security 包下的 Signature 类构造签名工具,签名方法使用“SHA256withRSA”;
- 使用initSign方法导入商户私钥isvPrivateKey 和字节数组byte[];
- 使用sign方法生成签名;
- 使用 Base64.encodeBase64URLSafeString 对签名进行编码;
- 在后面拼接“$SHA256”字符串。
c、计算签名示例
规范请求canonicalRequest:
yop-auth-v3/app_100123456789/2021-12-08T11:59:16Z/1800
POST
/rest/v1.0/trade/order
content-type:application%2Fx-www-form-urlencoded
x-yop-appkey:app_100123456789
x-yop-content-sha256:d9c89c72b774c89e2d15c19fc3326e7c9508d605a7974ab0a636d9121c97e7ff
x-yop-request-id:d48782ac-93c1-466e-b417-f7a71e4965f0
商户私钥isvPrivateKey:
RSA算法的商户私钥isvPrivateKey:
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC+YgO139eaN/Cjd3mTE4ePwqSI1F8ubXojffiwXy+mEiYGR4YscIcPQiYUGb2YpZQHa/Zoz+OyuloBCQBS1C8cva91KJojzUA4ll88vj8JF64G3P6WZh8acoUdNo8WRWfj9TVMMPBtzVcLK2bujrfx/t5Sggi66IK1FthcEtrkN8atA3rLj4OhNbZOzQRadecZDkeVelXU5LvNvBhBwO1cJ2Agr7ezkUaQENau/TSIAKdGJt607daB/MDgQdNrCNc/lUnp9+a8BUNYNCyJQZJKeAyVqFO73c/v3dlRaAUUfoH+hIbmS0g3aSpmxexvka6BFEld16wRG41VSGFhXbkRAgMBAAECggEASC9/uqkp5ZaKTmDRnvuLre2eVyc3A7KM2gI8lhsxROWit0TNUfJEs3tgVsS/x64YZ4v+/RS+ABl6YOQZ1E4RovMlIOYJM8PyMsKJT83OttLcsEuA2GPWLT/4yu/R5x7f2mYyFDaGIwv1kg2d1JwWkNITV/Nn/f6E+Ma1uIuJpXf9CVxIokfWFMstGNAGw/871V1qKAIDRsWTN4gTT4aRK/FPvQNzHv4nSEtlYdAYE8r53MaAZfigfFSOGowPFegyktQJXfmAUOhZbRhRZGQqcwU/1M5/TKu1cJECM/N/1ttjMlPNamQmONawq8dqfpK7a45YyWgyaadN2flA4/nWdQKBgQDWwrQsxnoVcoL88fFZYwol/5RYG+eA9zMffCi39KsKBU6ePbLlORYd2D/f2nDno6Uz2tFnUoRLvKy3ZINuIdN/jgD4ob69tk7XIKQSzh9Tv2485P8PasublywgdG9LnYk8qbF1VDsOkgecSSh7xG8Rz/U9p9kI5/wt3OOc0brjKwKBgQDi8PDtFziZNVSC58BcaWpAfZyDwB8X56BtNz1890zVOvF8ali6GUwgZkcH8KsQXhu+1YkmnC/YS6H0s+ZE4CIP6FGw5Z8988UB2i+oB0BMK8l8WDFOgPyW2n9l6502Qx1tqD3alekcksFsIlUgP9sVc5vtAKUPtNgguhRcP6mmswKBgQDCkkSLDIcvR0BFyy3OvlxDcPsFmMJ1pYE71VFO2Ozdd1FzLJMX+lB/WZ0FQvNn6muSP33ZDnmt5JLW1Mn+zcbAmfdnS6N0XeewIHKGVxkq1xUZNp+faDJwFNZ10QfEikX8IAIXOukGmmcqwV1cROwcRzz5T0jjOMrRAn91ZM7dYQKBgC91JVzfU0WuwlqRrkdlAAQ2gGmI3re4B3NvbttYN+gLaH6VGrLoIWRRHx+I86z7kR/KNeEuHk9EGb07dbcHi/f5pEOy8ScaeCNYBklEIu0K5xqqsrzw+mFtleCxcfHr/RZ2bWDtoo8IHYzIbTbOQ7lrsLrSPLJZJi1J3IIiCg9DAoGAOxT0qqTUADmSvwnzyQAYJ5sFI36eMcKqwkBuqb7ZQiLFNv1WZROrkeGin2ishntFKsIUtrpeikPjNP2AX6X0UuSQsUNNWx1zYpSlNUyGtGueYhmmP+7plPN5BhuJ3Ba6IYC/uI/l1tJP3S4e/xa/rCcNrf36RzK+PLLPq/uPAaY=
———————————————————————————————————————————————————————————————————————————
SM算法的商户私钥isvPrivateKey:
MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQg/WsUu5NQDTDJjjaXWLlNfBNZhamXAqCLcyLPSHDSD4qgCgYIKoEcz1UBgi2hRANCAAQUC8TdvSHnCXGlQzm62w+sqHK8wt/ZDXmuhyU4qOEJ8jRMiTzQWoX8BC0fB7ggzWIobHrJouBgnEm3AxVhShpZ
签名signature:
RSA算法生成的签名signature:
pOVoj1mI5bqYQQKTlE8iIYm0DKHpL5Q2vscY03lwP3KXpHRPJlKQfEOgpW-jfsyWf46c-uPehOZfOke7vla3rY6FtAVeoX0g8319WEdvQVgXwzW7xPtp5er4No8gpCrizsbmp2Fw7NSjASGsCaLEEri8iHsvN_TgFsGEIUf9JtQYWkoqdOh6vK1-xZvisp2ePAg2GKHy1Y0tbkXbzO9Bp_dBkgEHI7B2N80mzn-tEZ0xi6uMKSSvI8VPK14Rys8pJ4c4I4RZjoDEnxxsG2Z977RGtCuf_3RvrwohxECO5iF8BMjJF89nqi50QaZtS2mx32649_cORFLbD8VFpQhyxA$SHA256
——————————————————————————————————————————————————————————————————
SM算法生成的签名signature:
mLJb2KO9dH0Sb4n2EqZZRIkZut5lgDP-LHZhNZ2j0TggQ6gMzPem4sznJBvzDk0a--K9YfzUjQWZFPyFQUOgmA$SM3
二、常见问题
常见问题
Q:
如何做数字信封?
数字信封技术结合了对称密钥加密和公钥加密的优点,解决了对称密钥的发布安全问题和公钥加密速度慢问题,提高了安全性、扩展性和效率等。
甲使用对称密钥对明文进行加密,生成密文信息。
甲使用乙的公钥加密对称密钥,生成数字信封。
甲将数字信封和密文信息一起发送给乙。
乙接收到甲的加密信息后,使用自己的私钥打开数字信封,得到对称密钥。
乙使用对称密钥对密文信息进行解密,得到最初的明文。
Q:
什么是数字签名?
简单来说,签名主要包含两个过程:摘要和非对称加密,首先对需要签名的数据做摘要(类似于常见的MD5)后得到摘要结果,然后通过签名者的私钥对摘要结果进行非对称加密即可得到签名结果。
一个很好的说明文档可以参考:What is a Digital Signature?,中文翻译可以参考:数字签名是什么?