Skip to content

WPS-4签名说明

接口签名时,只签uri和query部分,不签域名+网关前缀,如:/o/cid/api/xxx?param=val,只签/api/xxx?param=val部分

Header说明

参数参数类型是否必须说明
Content-Typestring默认为"application/json",跟实际请求的ContentType保持一致
Wps-Docs-Datestring取当前时间, 格式: "Wed, 23 Jan 2013 06:43:08 GMT"
Wps-Docs-Authorizationstring签名值

计算方法如下:

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-Typestring固定为:"application/json"
Wps-Docs-Datestring取当前时间,格式:"Wed, 23 Jan 2013 06:43:08 GMT"
Wps-Docs-Authorizationstring签名值,格式:"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
}