WPS-4签名说明
接口签名时,只签uri和query部分,不签域名+网关前缀,如:/o/cid/api/xxx?param=val,只签/api/xxx?param=val部分
Header说明
| 参数 | 参数类型 | 是否必须 | 说明 |
|---|---|---|---|
| Content-Type | string | 是 | 默认为"application/json",跟实际请求的ContentType保持一致 |
| Wps-Docs-Date | string | 是 | 取当前时间, 格式: "Wed, 23 Jan 2013 06:43:08 GMT" |
| Wps-Docs-Authorization | string | 是 | 签名值 |
计算方法如下:
json
Wps-Docs-Authorization: "WPS-4 ${AppId}:${Signature}"
Signature: hmac-sha256(AppKey, Ver + HttpMethod + URI + Content-Type + Date + sha256(HttpBody))其中:
- Ver:WPS-4,表示算法版本,后续算法有更新,则变更该字段
- HttpMethod:表示HTTP 请求的Method的字符串,如PUT、GET、POST、HEAD、DELETE等
- URI:不带域名,如:"/api_url?app_id=aaaa"
- Content-Type:表示请求内容的类型,如:"application/json"
- Date:对签名时限进行验证
- HttpBody:如果为空,则sha256(body)部分取空串
注意:sha256与hmac-sha256均取小写十六进制字符串
Go代码示例
go
// Wps4DocsSign Wps4Docs签名
// url: 包含path和query,如:/api/v1/info?a=b
func Wps4DocsSign(ak, sk, url, method, contentType string, body []byte) (*Wps4DocsHeader, error) {
if ak == "" || sk == "" || url == "" || method == "" {
return nil, el.New(el.CodeParamFormatError, "sign params error: ak、sk、url、method can not be empty ")
}
// 1. 计算content sha256值
// HTTP Body中数据的sha256值十六进制表达方式
// body为空时,则sha256(body部分取空串)
sha256Hex := ""
if len(body) > 0 {
s := sha256.New()
s.Write(body)
sha256Hex = hex.EncodeToString(s.Sum(nil))
}
// 2. 计算authorization
mac := hmac.New(sha256.New, []byte(sk))
date := time.Now().UTC().Format(http.TimeFormat)
mac.Write([]byte(Wps4DocsType + method + url + contentType + date + sha256Hex))
macHex := hex.EncodeToString(mac.Sum(nil))
authorization := fmt.Sprintf("%s %s:%s", "WPS-4", ak, macHex)
return &Wps4DocsHeader{
ContentType: contentType,
Date: date,
Authorization: authorization,
}, nil
}Java代码示例
java
public static String getWPS4Authorization(String ak, String sk, String method, String path, String contentType, Map<String, String> arguments, String userDate) {
path = path.substring(path.indexOf("/v1"));
StringBuilder encodedParams = new StringBuilder();
int count = 0;
if (null != arguments)
for (Map.Entry<String, String> entry : arguments.entrySet()) {
String encodeKey = null;
try {
encodeKey = URLEncoder.encode(entry.getKey(), "UTF-8");
String encodeValue = URLEncoder.encode(entry.getValue(), "UTF-8");
encodedParams.append(encodeKey).append("=").append(encodeValue);
if (count < arguments.size() - 1) {
encodedParams.append("&");
}
count++;
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
String body = encodedParams.toString();
String date;
if (userDate == null)
date = getGMTDateString();
else
date = userDate;
String authorization;
if (body.isEmpty()) {
authorization = "WPS-4" + method + path + contentType + date;
} else {
String hashedBody = sha256Hex(body);
authorization = "WPS-4" + method + path + contentType + date + hashedBody;
}
String hmacHash = hmacSha256Hex(sk, authorization);
authorization = "WPS-4 " + ak + ":" + hmacHash;
return authorization;
}sha256和hmac工具类代码:
package demo.utils;
import javax.crypto.Mac;import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class HMacUtils {
public static String HMACSHA256(String data, String key) throws Exception {
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"),"HmacSHA256");
sha256_HMAC.init(secret_key);
byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8"));StringBuilder sb = new StringBuilder();
for (byte item : array) {
sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1,3));
}
return sb.toString();
}
/**
* 利用java原生的摘要实现SHA256加密
* @param str 加密后的报文
* @return
*/
public static String getSHA256StrJava(byte[] str){
MessageDigest messageDigest;
String encodeStr = "";
try {
messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(str);
encodeStr = byte2Hex(messageDigest.digest());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return encodeStr;
}
/**
* 将byte转为16进制* @param bytes* @return*/
private static String byte2Hex(byte[] bytes){
StringBuffer stringBuffer = new StringBuffer();String temp = null;
for (int i=0;i<bytes.length;i++){
temp = Integer.toHexString(bytes[i] & 0xFF);
if (temp.length()==1){
//1得到一位的进行补0操作
stringBuffer.append("0");
}
stringBuffer.append(temp);
}
return stringBuffer.toString();
}
}JS代码示例
javascript
var accessKey = pm.environment.get("accessKey");
var secretKey = pm.environment.get("secretKey");
// 获取请求信息
var method = pm.request.method;
var path = pm.environment.replaceIn(pm.request.url.getPathWithQuery());
var body = pm.environment.replaceIn(pm.request.body.toString());
var contentType = "application/json";
var dateString = new Date().toGMTString();
var authorization = "";
if (body == "") {
authorization = "WPS-4" + method + path + contentType + dateString;
} else {
authorization =
"WPS-4" +
method +
path +
contentType +
dateString +
CryptoJS.SHA256(body).toString(CryptoJS.enc.Hex);
}
authorization = CryptoJS.HmacSHA256(authorization, secretKey).toString(
CryptoJS.enc.Hex
);
authorization = "WPS-4 " + accessKey + ":" + authorization;
// 设置请求头
pm.request.headers.upsert({
key: "Wps-Docs-Date",
value: dateString,
});
pm.request.headers.upsert({
key: "Content-Type",
value: contentType,
});
pm.request.headers.upsert({
key: "Wps-Docs-Authorization",
value: authorization,
});WPS-4-GM签名
1.1 签名算法说明
接口鉴权需要wps4签名的接口,header中需要携带以下字段:
| 参数 | 参数类型 | 是否必须 | 说明 |
|---|---|---|---|
| Content-Type | string | 是 | 固定为:"application/json" |
| Wps-Docs-Date | string | 是 | 取当前时间,格式:"Wed, 23 Jan 2013 06:43:08 GMT" |
| Wps-Docs-Authorization | string | 是 | 签名值,格式:"WPS-4 $access_key:$Signature" |
1.2 Wps-Docs-Authorization计算方法
接口签名时,只签uri字段,不签域名,具体计算规则如下:
javascript
Wps-Docs-Authorization:"WPS-4-GM $access_key:$Signature"
Signature:hmac-sm3(secret_key, Ver + HttpMethod + URI + Content-Type + Wps-Docs-Date + sm3(HttpBody))Ver + HttpMethod + URI + Content-Type + Wps-Docs-Date + sm3(HttpBody) 示例:
javascript
WPS-4-GMPOST/callback/path/demoapplication/jsonWed, 20 Apr 2022 01:33:07 GMTfc005f51a6e75586d2d5d078b657dxxxdf9c1dfa6a7c0c0ba38c715daeb6ede9- Ver: WPS-4-GM,表示算法版本,后续算法有更新,则变更该字段。
- HttpMethod:表示HTTP 请求的Method的字符串,如PUT、GET、POST、HEAD、DELETE等。
- URI:不带域名,如:"/api_url?app_id=aaaa"。
- Content-Type:表示请求内容的类型,如:"application/json"。
- Wps-Docs-Date:自行对签名时限进行验证。
- HttpBody:如果为空,则sm3(body)部分取空串。
1.3 Go代码示例
go
const (
Wps4GmDocsType = "WPS-4-GM"
DefaultContentTypeValue = "application/json"
ContentTypeHeaderKey = "Content-Type"
WpsDocsDateHeaderKey = "Wps-Docs-Date"
WpsDocsAuthHeaderKey = "Wps-Docs-Authorization"
)
func (w *Wps4GmDocsAuth) Sign(r *http.Request) (*Wps4GmDocsHeader, error) {
authorization := ""
contentType := r.Header.Get(ContentTypeHeaderKey)
date := r.Header.Get(WpsDocsDateHeaderKey)
// 1. 计算content sm3值
// HTTP Body中数据的sm3值十六进制表达方式
// body为空时,则sm3(body部分取空串)
body, err := ioutil.ReadAll(r.Body)
r.Body = ioutil.NopCloser(bytes.NewReader(body))
if err != nil {
return nil, el.New(el.CodeAuthError, "sign fails: read body error", el.String(SignTypeKey, Wps4GmDocsType))
}
sm3Hex := ""
if len(body) > 0 {
s := sm3.New()
s.Write(body)
sm3Hex = hex.EncodeToString(s.Sum(nil))
}
// 2. 计算authorization
mac := hmac.New(sm3.New, []byte(w.SecretKey))
httpMethod := r.Method
url := r.URL.RequestURI()
mac.Write([]byte(Wps4GmDocsType + httpMethod + url + contentType + date + sm3Hex))
macHex := hex.EncodeToString(mac.Sum(nil))
authorization = Wps4GmDocsType + " " + w.AccessKey + ":" + macHex
return &Wps4GmDocsHeader{
ContentType: contentType,
Date: date,
Authorization: authorization,
}, nil
}