md5

使用方式

签名算法

MD5

待签名参数

获取所有请求参数(防止新增参数导致签名失败),除去 sign,其他请求参数(包含空值的参数,即 key="" )都要参加验签。

详细步骤

STEP1:获取签名密钥
STEP2:参数拼接,获取 $source 字符串
  1. 对所有待签名参数按照字段名的ASCII码从小到大排序;
  2. 使用键值对的格式( key1=value1&key2=value2 )连接参数,拼接成字符串;
  3. 对拼接完参数的字符串进行 urlencode 编码,获得 $source 字符串;

其中,value 的定义如下:

类型 定义
string 直接拼接字符串内容即可,没有引号,如:abc
number 需要转成字符串后拼接,如:1231.03
bool 需要转成 true/false 后拼接
空(null) 需要转成空字符串("")后拼接
list 一般会转为 string 的方式来使用,不会直接使用 list 结构本身
object 一般会转为 string 的方式来使用,不会直接使用 object 结构本身
STEP3:利用密钥生成请求参数的签名摘要
  1. 将上述 $source 字符串与秘钥 AppSecret(签名密钥) 通过 & 符号进行拼接,即:$source&AppSecret(签名密钥)
  2. 将拼接后的字符串进行MD5哈希签名得到最终 sign 值(长度为32);
  3. sign 值作为请求参数的一部分,发送到服务端进行鉴权。

使用举例

假设 AppSecret(签名密钥)38f9c7af24ff11edb92900163e30ef81,请求参数为:

  • b = 1
  • a = "飞鱼"
  • d = 0.1
  • c = null
  • x = true
  • y = false

实际计算步骤如下:

  1. 通过步骤2的排序和连接,可以得到:a=飞鱼&b=1&c=&d=0.1&x=true&y=false
  2. 通过步骤2的 urlencode 编码,可以得到 a%3D%E9%A3%9E%E9%B1%BC%26b%3D1%26c%3D%26d%3D0.1%26x%3Dtrue%26y%3Dfalse
  3. 通过步骤3的尾部追加 AppSecret(签名密钥),可以得到:a%3D%E9%A3%9E%E9%B1%BC%26b%3D1%26c%3D%26d%3D0.1%26x%3Dtrue%26y%3Dfalse&38f9c7af24ff11edb92900163e30ef81
  4. 计算 MD5 哈希值,得到 sign 值: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 == "sign" {
            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 == 'sign'){
            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计算签名
}