使用方式
签名算法
MD5
待签名参数
获取所有请求参数(防止新增参数导致签名失败),除去 sig
,其他请求参数(包含空值的参数,即 key=""
)都要参加验签。
详细步骤
STEP1:获取签名密钥
STEP2:参数拼接,获取 $source
字符串
- 对所有待签名参数按照字段名的ASCII码从小到大排序;
- 使用键值对的格式(
key1=value1&key2=value2
)连接参数,拼接成字符串; - 对拼接完参数的字符串进行
urlencode
编码,获得$source
字符串;
其中,value 的定义如下:
类型 | 定义 |
---|---|
string | 直接拼接字符串内容即可,没有引号,如:abc |
number | 需要转成字符串后拼接,如:123 、1.03 |
bool | 需要转成 true /false 后拼接 |
空(null) | 需要转成空字符串("" )后拼接 |
list | 一般会转为 string 的方式来使用,不会直接使用 list 结构本身 |
object | 一般会转为 string 的方式来使用,不会直接使用 object 结构本身 |
STEP3:利用密钥生成请求参数的签名摘要
- 将上述
$source
字符串与秘钥AppSecret(签名密钥)
通过&
符号进行拼接,即:$source
&AppSecret(签名密钥)
; - 将拼接后的字符串进行MD5哈希签名得到最终
sig
值(长度为32); - 将
sig
值作为请求参数的一部分,发送到服务端进行鉴权。
使用举例
假设 AppSecret(签名密钥)
为 38f9c7af24ff11edb92900163e30ef81
,请求参数为:
- b = 1
- a = "飞鱼"
- d = 0.1
- c =
null
- x =
true
- y =
false
实际计算步骤如下:
- 通过步骤2的排序和连接,可以得到:
a=飞鱼&b=1&c=&d=0.1&x=true&y=false
- 通过步骤2的
urlencode
编码,可以得到a%3D%E9%A3%9E%E9%B1%BC%26b%3D1%26c%3D%26d%3D0.1%26x%3Dtrue%26y%3Dfalse
- 通过步骤3的尾部追加
AppSecret(签名密钥)
,可以得到:a%3D%E9%A3%9E%E9%B1%BC%26b%3D1%26c%3D%26d%3D0.1%26x%3Dtrue%26y%3Dfalse&38f9c7af24ff11edb92900163e30ef81
- 计算 MD5 哈希值,得到
sig
值:b224b5e297129bbc9e15d90a168c0a3f
签名样例
Golang
package main
import (
"crypto/md5"
"encoding/hex"
"net/url"
"sort"
"strconv"
"strings"
)
func Sign(params map[string]interface{}, appSecret string) string {
keys := make([]string, 0, len(params))
for k := range params {
keys = append(keys, k)
}
// 对key进行排序
sort.Strings(keys)
var kvPairs []string
for _, k := range keys {
if k == "sig" {
continue
}
v := params[k]
strValue := ""
if v != nil {
switch v := v.(type) {
case float32, float64:
// 浮点类型需要特殊处理,不然转换后的字符串会变成科学计数法的形式导致签名url不正确
strValue = strconv.FormatFloat(v.(float64), 'f', -1, 64)
default:
strValue = fmt.Sprintf("%v", v)
}
}
kvPairs = append(kvPairs, k+"="+strValue)
}
// 拼接参数
source := strings.Join(kvPairs, "&")
// 进行urlencode编码
source = strings.Replace(url.QueryEscape(source), "+", "%20", -1)
// 拼接AppSecret
source += "&" + appSecret
// 生成MD5签名
hash := md5.Sum([]byte(source))
sign := hex.EncodeToString(hash[:])
return sign
}
PHP
function sign($params, $appSecret)
{
ksort($params);//1 按照健值从小到大排序
$signParams = array();//2 键值对按照'='拼接,排除sign参数
foreach ($params as $key => $val) {
if ($key == 'sig'){
continue;
}
switch (gettype($val)) {
case 'NULL':
$val = '';
break;
case 'boolean':
$val = $val === true ? 'true' : 'false';
break;
default:
$val = (string) $val;
break;
}
array_push($signParams, $key . '=' . $val);
}
$signStr = join('&', $signParams);//3 将上述数组按照&拼接
$source = rawurlencode($signStr);//4 将拼接结果用rawurlencode编码
return md5($source.'&'. $appSecret);//md5 hash计算签名
}