前沿

api接口作为越来越常用的东西,我们开放了一个api接口,那么我们必须考虑到安全问题,还有权限问题,只有经过授权的人才可以使用,这里我们就用到了现在最常用的参数签名,下面我们一起来看看吧。

签名的算法

假设参与参数签名计算的请求参数分别是 k1=v1,k2=v2,k3=v3
为了更进一步的安全验证,要求再加一个当前时间的参数,格式为:YYYYMMDDHHIISS。
如:timestamp=20191019152025
将参数键值对以字典序升序排列后,参数和值拼接在一起,即 k1v1k2v2k3v3timestamp20191019152025
将分配的密钥(secret)拼接在最后,假设密钥 secret=abcdefg ,那么最后拼拼接好的字符串为:k1v1k2v2k3v3timestamp20191019152025abcdefg
最后进行md5加密并转为大写,得到的值就是签名的值,即 sign=2102E0C5166ED9857078449572944335

签名计算好后把签名和分配的id连同本来的参数一起传过去就行了,即:

  1. xx.xx?k1=v1&k2=v2&k3=v3&timestamp=20191019152025&appid=aa&sign=2102E0C5166ED9857078449572944335


实例 以PHP为例

接口提供方

<?php

/**
 * 校验签名
 * @param $param  array  参数数组
 * @param $secret string 密钥
 * @return bool
 */
function checkSign($param,$secret){
    $sign = $param['sign'];
    unset($param['sign']);

    ksort($param);
    $param_str = '';
    foreach ($param as $k => $v){
        $param_str .= $k . $v;
    }
    if (strtoupper(md5($param_str . $secret)) === $sign){
        return true;
    }
    return false;
}

/**
 * 校验时间,允许误差为30秒
 * @param $timestamp string 参数里的时间字符串
 * @return bool
 */
function checkTimestamp($timestamp){
    $paramTime = strtotime($timestamp);
    $time = time();
    $max  = $time + 30;
    $min  = $time - 30;
    if ($paramTime <= $max && $paramTime >= $min){
        return true;
    }
    return false;
}

/**
 * 校验用户
 * @param $appid string  用户的appid
 * @return mixed|string
 */
function checkUser($key){
    //假设授权了(aa,bb,cc)三位用户,可以使用此接口
    $user = [
        'aa' => 'asdfghjkl',
        'bb' => 'qwertyuiop',
        'cc' => 'zxcvbnm',
    ];

    return $user[$key] ?? false;
}


$a = checkUser($_GET['appid']);
$b = checkSign($_GET,$a);
$c = checkTimestamp($_GET['timestamp']);

echo json_encode([
    'checkUser'      => $a ? true : false,
    'checkSign'      => $b,
    'checkTimestamp' => $c
]);

接口使用方

<?php

const APP_ID = 'aa';       //分配的appid
const SECRET = 'asdfghjkl';//分配的密钥,不当参数传过去
$param = [
    'id'        => 123,
    'name'      => '小明',
    'age'       => 10,
    'q'         => '1 1',
    'appid'     => APP_ID,
    'timestamp' => date('YmdHis'),
];

$param['sign'] = sign($param,SECRET);
//curl为自己写的curl函数,这里就不写出来了
//说一下参数吧,第一个是地址,第二个是参数数组,第三个是是否post提交,第四个是是否https
$res = curl('localhost/test.php',$param,false,false);
print_r(json_decode($res,true));

/**
 * 生成签名
 * @param $param  array     参数数组
 * @param $secret string    访问密钥
 * @return string
 */
function sign($param,$secret){
    ksort($param);
    $param_str = '';
    foreach ($param as $k => $v){
        $param_str .= $k . $v;
    }
    return strtoupper(md5($param_str . $secret));
}

运行上面的代码,我们可以看到

Array ( [checkUser] => 1 [checkSign] => 1 [checkTimestamp] => 1 )