Skip to content

签名说明

接口签名时,只签uri字段(不包含/openapi部分),不签域名,如:/openapi/v7/api/xxx,只签/v7/api/xxx部分

Header说明

Header名称参数类型是否必填说明
Content-Typestring如:"application/json",跟实际请求的Content-Type保持一致即可,GET请求的Content-Type可为空
X-Kso-DatestringRFC1123 格式的日期,例:`Wed, 23 Jan 2013 06:43:08 GMT`
X-Kso-AuthorizationstringKSO-1 签名值。格式为:`KSO-1 accessKey:signature`

X-Kso-Authorization 说明:

  1. KSO-1:签名算法版本,此处目前固定为 KSO-1(注意: 后面有一个空格)
  2. accessKey:应用的 APPID(注意: 后面有一个英文冒号:
  3. signature:使用 secretKey(应用 APPKEY) 作为密钥、SHA256 作为哈希算法, 通过 HMAC-SHA256 编码内容:
json
"KSO-1" + Method + RequestURI + ContentType + KsoDate + sha256(RequestBody)
  • "KSO-1":固定内容,签名版本字符串
  • Method:请求的方法
  • RequestURI:请求的 URI,包含 query 参数,例:/v7/users?page_size=20&page_token=aabb
  • KsoDate:RFC1123 格式的日期
  • sha256(RequestBody):当请求体不为空时,使用 SHA256 哈希算法计算请求体的值;如果为空时,sha256(RequestBody)部分取空串

示例

示例1

示例的 RequestBody = "",为空

json
// 请求参数
accessKey = "****************"
secretKey = "********************************"
Method = "GET"
RequestURI = "/v7/test?key=value"
ContentType = "application/json"
KsoDate = "Mon, 02 Jan 2006 15:04:05 GMT"
RequestBody = ""

// 计算结果
sha256(RequestBody) = ""
Content-Type = "application/json"
X-Kso-Date = "Mon, 02 Jan 2006 15:04:05 GMT"
X-Kso-Authorization = "KSO-1 AK****************:SK********************************"

示例2

示例的 RequestBody = {"key": "value"},JSON 数据

json
// 请求参数
accessKey = "AK****************"
secretKey = "SK********************************"
Method = "POST"
RequestURI = "/v7/test/body"
ContentType = "application/json"
KsoDate = "Mon, 02 Jan 2006 15:04:05 GMT"
RequestBody = `{"key": "value"}`            // 注意 json 格式,会影响到签名计算

// 计算结果
sha256(RequestBody) = "9724c1e20e6e3e4d7f57ed25f9d4efb006e508590d528c90da597f6a775c13e5"
Content-Type = "application/json"
X-Kso-Date = "Mon, 02 Jan 2006 15:04:05 GMT"
X-Kso-Authorization = "KSO-1 AK****************:SK**************************************************************"

Golang代码示例

签名算法示例

go
package main

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"errors"
	"fmt"
)

type KsoSign struct {
	accessKey string
	secretKey string
}

type Out struct {
	Date          string // X-Kso-Date
	Authorization string // X-Kso-Authorization
}

func NewKsoSign(accessKey, secretKey string) (*KsoSign, error) {
	if accessKey == "" || secretKey == "" {
		return nil, errors.New("NewKsoSign error: AccessKey/SecretKey can not be empty")
	}
	return &KsoSign{
		accessKey: accessKey,
		secretKey: secretKey,
	}, nil
}

func (k *KsoSign) getKso1Signature(secretKey, method, uri, ksoDate, contentType string, requestBody []byte) string {
	sha256Hex := ""
	if len(requestBody) > 0 {
		s := sha256.New()
		s.Write(requestBody)
		sha256Hex = hex.EncodeToString(s.Sum(nil))
	}

	mac := hmac.New(sha256.New, []byte(secretKey))
	mac.Write([]byte("KSO-1" + method + uri + contentType + ksoDate + sha256Hex))
	return hex.EncodeToString(mac.Sum(nil))
}

func (k *KsoSign) KSO1Sign(method, uri, contentType, ksoDate string, body []byte) (*Out, error) {
	ksoSignature := k.getKso1Signature(k.secretKey, method, uri, ksoDate, contentType, body)
	authorization := fmt.Sprintf("%s %s:%s", "KSO-1", k.accessKey, ksoSignature)
	return &Out{
		Date:          ksoDate,
		Authorization: authorization,
	}, nil
}

func main() {
	accessKey := "AK****************"
	secretKey := "SK**************************************************************"
	method := "POST"
	uri := "/v7/test/body"
	contentType := "application/json"
	ksoDate := "Mon, 02 Jan 2006 15:04:05 GMT"
	body := `{"key": "value"}` // 注意 json 格式,会影响到签名计算

	sign, err := NewKsoSign(accessKey, secretKey)
	if err != nil {
		panic(err)
	}

	out, err := sign.KSO1Sign(method, uri, contentType, ksoDate, []byte(body))
	if err != nil {
		panic(err)
	}
	fmt.Printf("out: %v\n", out)
	// 输出:out: &{Mon, 02 Jan 2006 15:04:05 GMT KSO-1 AK123456:c46e6c988130818ecba2484d51ac685948fbbef6814602c7874d6bfc41dc17b3}
}

Java 代码示例

签名方法示例

java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class KsoSign {
    private final String accessKey;
    private final String secretKey;

    public KsoSign(String accessKey, String secretKey) {
        this.accessKey = accessKey;
        this.secretKey = secretKey;
    }

    public static final class Out {
        private final String date;  // X-Kso-Date
        private final String authorization;  // X-Kso-Authorization

        public Out(String date, String authorization) {
            this.date = date;
            this.authorization = authorization;
        }

        public String getDate() {
            return date;
        }

        public String getAuthorization() {
            return authorization;
        }
    }

    public Out kso1Sign(String method, String uri, String contentType, String ksoDate, byte[] requestBody) throws NoSuchAlgorithmException, InvalidKeyException {
        String ksoSignature = getKso1Signature(method, uri, contentType, ksoDate, requestBody);
        String authorization = String.format("KSO-1 %s:%s", accessKey, ksoSignature);
        return new Out(ksoDate, authorization);
    }

    private String getKso1Signature(String method, String uri, String contentType, String ksoDate, byte[] requestBody) throws NoSuchAlgorithmException, InvalidKeyException {
        String sha256Hex = "";
        if (requestBody != null && requestBody.length > 0) {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] hash = digest.digest(requestBody);
            sha256Hex = bytesToHex(hash);
        }

        System.out.println("sha256: " + sha256Hex);

        String dataToSign = "KSO-1" + method + uri + contentType + ksoDate + sha256Hex;
        Mac mac = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
        mac.init(secretKeySpec);
        byte[] macBytes = mac.doFinal(dataToSign.getBytes(StandardCharsets.UTF_8));
        return bytesToHex(macBytes);
    }

    private String bytesToHex(byte[] bytes) {
        StringBuilder result = new StringBuilder();
        for (byte b : bytes) {
            result.append(String.format("%02x", b));
        }
        return result.toString();
    }
}

//

public class Main {
    public static void main(String[] args) throws Exception {
        final String accessKey = "AK***********************";
        final String secretKey = "SK**************************************************************";
        final String method = "POST";
        final String uri = "/v7/test/body";
        final String contentType = "application/json";
        final String contentDate = "Mon, 02 Jan 2006 15:04:05 GMT";
        final byte[] requestBody = "{\"key\": \"value\"}".getBytes(StandardCharsets.UTF_8);

        KsoSign kso = new KsoSign(accessKey, secretKey);
        KsoSign.Out out = kso.kso1Sign(method, uri, contentType, contentDate, requestBody);
        System.out.println(out.getDate());
        System.out.println(out.getAuthorization());
    }
}

Python 代码示例

签名方法示例

python
import hashlib
import hmac
import http

ACCESS_KEY = 'AK***********************'
SECRET_KEY = 'SK**************************************************************'


def _get_kso1_signature(method, uri, content_type, kso_date, request_body):
    sha256_hex = ''
    if request_body is not None and len(request_body) > 0:
        sha256_obj = hashlib.sha256()
        sha256_obj.update(request_body.encode())
        sha256_hex = sha256_obj.hexdigest()

    mac = hmac.new(bytes(SECRET_KEY, 'utf-8'),
                   bytes('KSO-1' + method + uri + content_type + kso_date + sha256_hex, 'utf-8'),
                   hashlib.sha256)
    return mac.hexdigest()


def kso1_sign(method, uri, content_type, kso_date, request_body):
    kso_signature = _get_kso1_signature(method, uri, content_type, kso_date, request_body)
    authorization = 'KSO-1 {}:{}'.format(ACCESS_KEY, kso_signature)
    return {
        'X-Kso-Date': kso_date,
        'X-Kso-Authorization': authorization
    }


if __name__ == '__main__':
    def test():
        method = http.HTTPMethod.POST
        uri = '/v7/test/body'
        content_type = 'application/json'
        kso_date = 'Mon, 02 Jan 2006 15:04:05 GMT'
        request_body = '{"key": "value"}'

        res = kso1_sign(method, uri, content_type, kso_date, request_body)
        print(res)


    test()