Signature

Signature

If the SDK list contains the language you are working with, you can use the corresponding SDK and ignore the following signing algorithm, which is automatically signed during the call.

Data Assumptions

When generating the signature (Signature) in the API request, you need to provide the account's keys, including PublicKey and PrivateKey, Keys can be obtained from the PICPIK User Center (opens in a new tab).

In this example, assume

PublicKey  = 'abcdefg'
PrivateKey = '123456'

You can use the above PublicKey and PrivateKey to debug your code. When you get the same signature result as below (indicating that your code is correct), you can replace it with your own PublicKey, PrivateKey, and other API requests.

In this example, assume the user's request parameters are as follows:

💡

In practice, it should include all parameters you need except Signature.

{
    "Action"     :  "ListModels",
    "PublicKey"  :  "abcdefg"
}

Constructing the Signature

💡

Constructing the signature directly using the Sign function in demo codes is recommended if it includes the language you are using, which automatically handles complex data structures.

If the demo codes do not contain the language you prefer, please contact us to add it or generate a signature according to the following rules:

1. Sort the Request Parameters in Ascending Order by Name

{
    "Action"     :  "ListModels",
    "PublicKey"  :  "abcdefg"
}

2. Construct the String to Be Signed

The construction rule of the string to be signed is: the string to be signed = concatenation of all request parameters (no need for HTTP escape). And concatenate the private key (PrivateKey) of the API key at the end of this signature string.

ActionListModelsPublicKeyabcdefg123456

Note:

  • For bool type, it should be encoded as true/false, lowercase initial letters are required.
  • For floating-point number type, if the decimal part is 0, only the integer part should be retained, such as 42.0 should be retained as 42
  • For floating-point number type, scientific notation should not be used
  • For array types, convert each element of the array directly to string concatenation
  • For the map type, each field is sorted in ascending order by name, and then the name and value of each field are concatenated

3. Calculate the Signature

Use SHA1 encoding for the string to be signed to generate the final signature, which is the value of the request parameter Signature.

According to the above algorithm, in this example, the calculated Signature is 4a20bc1141494035f6aaaad13224c94c5a8bc3a5.

Demo Codes

func TestGenerateApiKey(t *testing.T) {
	var (
		PublicKey  = "abcdefg"
		PrivateKey = "123456"
		req        = map[string]interface{}{
			"Action":    "ListModels",
			"PublicKey": PublicKey,
		}
	)
	sign := Sign(req, PrivateKey)
	fmt.Println(sign)
}
// Sign generate signature
func Sign(params map[string]interface{}, privateKey string) string {
	str := map2String(params) + privateKey
 
	hashed := sha1.Sum([]byte(str))
	return hex.EncodeToString(hashed[:])
}
 
// simple2String convert map type to string
func map2String(params map[string]interface{}) (str string) {
	for _, k := range extractSortedKeys(params) {
		str += k + any2String(params[k])
	}
	return
}
 
// any2String convert any type to string
func any2String(v interface{}) string {
	switch v := v.(type) {
	case string, bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64:
		return simple2String(v)
	case []interface{}:
		return slice2String(v)
	case map[string]interface{}:
		return map2String(v)
	default:
		return reflectArr2String(reflect.ValueOf(v))
	}
}
 
// simple2String convert slice type to string
func slice2String(arr []interface{}) (str string) {
	for _, v := range arr {
		switch v := v.(type) {
		case string, bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64:
			str += simple2String(v)
		case []interface{}:
			str += slice2String(v)
		case map[string]interface{}:
			str += map2String(v)
		default:
			str += reflectArr2String(reflect.ValueOf(v))
		}
	}
	return
}
 
// simple2String convert simple type to string
func simple2String(v interface{}) string {
	return  fmt.Sprintf("%v",v)
}
 
// reflectArr2String convert array and slice to string in reflect way
func reflectArr2String(rv reflect.Value) (str string) {
	if rv.Kind() != reflect.Array && rv.Kind() != reflect.Slice {
		return
	}
 
	for i := 0; i < rv.Len(); i++ {
		str += any2String(rv.Index(i).Interface())
	}
	return
}
 
// extractSortedKeys extract all sorted keys from map[string]interface{}
func extractSortedKeys(m map[string]interface{}) []string {
	keys := make([]string, 0, len(m))
	for k := range m {
		keys = append(keys, k)
	}
 
	sort.Strings(keys)
	return keys
}