api接口签名加密请求(二)

知兮丶青
阅读(1513) 2018-01-12
api接口签名加密请求(二)
api接口签名加密请求(二)

在“api接口签名加密请求,从springmvc4项目搭建开始”篇文章,讲述了使用java springmvc搭建api接口请求例子。为了方便php能调用,接着写了php的demo例子。



回顾上回

api接口设计方式和思路

1、公开性

接口是公网可访问的,不希望被随便请求,需要token签名认证才能调用,接口提供方提供接口密钥。

2、安全性

模拟支付宝接口签名方式签名,请求参数按照key=value&key=value方式拼接的未签名原始字符串(含时间戳),再对原始字符串进行签名(加密钥)。如:md5(id=1&timestamp=1514020967 + 密钥)

3、模式性

请求

请求参数 + 时间戳 + 签名(请求参数+时间戳+密钥)

接收

md5(接收参数(去除签名) + 密钥) == 接收参数(签名)


后再比较 接收参数(时间戳) 跟 当前系统时间戳 的时效性



签名请求函数

/** 密钥 */
define("KEY","weizhixi");

/** 模拟post */
function curl_post($url, $params){
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_HEADER, 0);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
    curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type:application/x-www-form-urlencoded; charset=utf-8']);
    curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'POST');
    curl_setopt($curl, CURLOPT_POSTFIELDS,  $params);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    $data = curl_exec($curl);
    if($data === false)
        echo 'Curl error: ' . curl_error($curl);
    curl_close($curl);
    return $data;
}

/** 模拟get */
function curl_get($url, $params){
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url.'?'.$params);
    curl_setopt($curl, CURLOPT_HEADER, 0);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
    curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type:application/x-www-form-urlencoded; charset=utf-8']);
    curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'GET');
    $data = curl_exec($curl);
    if($data === false)
        echo 'Curl error: ' . curl_error($curl);
    curl_close($curl);
    return $data;
}

/**
 * 生成签名
 * 除去数组中的空值和签名参数
 * 对数组排序,把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
 * @param $params 需要签名的数组
 * @return md5签名
 */
function buildSign($params) {
    //去数组中的空值和签名
    $para = array();
    while (list ($key, $val) = each ($params)){
        if($key == "sign" || $val === "" || $val === null){
            continue;
        }else{
            $para[$key] = $params[$key];
        }
    }
    //对数组排序
    ksort($para);
    reset($para);
    //生成,参数=参数值
    $arg  = "";
    while (list ($key, $val) = each ($para)){
        if(is_array($val)){
            $val = implode(",",$val);
        }
        $arg .= $key."=".$val."&";
    }
    //去掉最后一个&字符
    $arg = substr($arg,0,count($arg)-2);
    //如果存在转义字符,那么去掉转义
    if(get_magic_quotes_gpc())
        $arg = stripslashes($arg);
    //签名
    return md5($arg . KEY);
}

/**
 * 验证签名
 * @param $params 返回来的参数数组
 * @return 签名验证结果
 */
function verifySign($params) {
    //返回的签名结果
    $sign = $params['sign'];
    $timestamp = $params['timestamp'];
    //我的签名
    $mySgin = buildSign($params);
    if ($mySgin == $sign) {
        //时间不能为空
        if(empty($timestamp))
            return false;
        var_dump(time() ."-". $timestamp);
        //是否超时
        if((time() - $timestamp) > 15)
            return false;
        return true;
    } else {
        return false;
    }
}

/**
 * 生成要请求的参数数组
 * @param $params 请求前的参数数组
 * @return 要请求的参数字符串
 */
function signString($params) {
    //生成签名
    $params['timestamp'] = time();
    $params['sign'] = buildSign($params);
    return createLinkStringUrlEncode($params);
}

/**
 * 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串,并对字符串做urlencode编码
 * @param $para 需要拼接的数组
 * @return string 拼接完成以后的字符串
 */
function createLinkStringUrlEncode($para) {
    $arg  = "";
    while (list ($key, $val) = each ($para)) {
        if(is_array($val)){
            while (list ($k, $v) = each ($val)) {
                //$arg.=$key."[]=".urlencode($v)."&";
                $arg.=$key."=".urlencode($v)."&";
            }
        }else{
            $arg.=$key."=".urlencode($val)."&";
        }
    }
    //去掉最后一个&字符
    $arg = substr($arg,0,count($arg)-2);
    //如果存在转义字符,那么去掉转义
    if(get_magic_quotes_gpc()){$arg = stripslashes($arg);}
    return $arg;
}


使用示例:

调用api请求:

$url = "http://localhost:8080/api/v1/index/save";
$params = array(
    "id" => "1",
    "name" => "微知兮",
    "tags" => array("1","2","3")
);
$params = signString($params);
$result = curl_post($url, $params);
print_r(json_decode($result, true));


验证请求:

if(verifySign($_POST)){
    echo '验证成功';
}else{
    echo '验证失败';
}


至此,api已经介绍完毕,已附上java完整例子和php版例子,如需要请自行下载,如需要可看回java的版本文章。


本例子仅供学习研究,由于写的比较仓促,如有不妥当的地方欢迎指出。



zip icon
api接口签名加密请求(完整版).zip 003c8f71341f08cd636ff89c54c87f1a

已下载:526

已下载:840

原创文章,转载请注明出处:https://www.weizhixi.com/article/58.html