PHP接口签名校验

项目中常用的API接口签名验证方法:

1.给app分配对应的appId、appKey 2. Sign签名,调用API 时需要对请求参数进行签名验证,签名方式如下:

a. 按照请求参数名称将所有请求参数按照键名进行升序排序,如:将arong=1,mrong=2,crong=3 排序为:arong=1, crong=3,mrong=2 然后将参数名和参数值进行拼接得到参数字符串:arong=1&crong=3&mrong=2

b. 将appKey加在参数字符串的尾部&key=appKey后进行MD5加密 ,加密后的字符串需转小写。即得到签名Sign;

php签名类

<?php
/**
 * Created by PhpStorm.
 * User: Pasa吴
 * Date: 2023/1/2
 * Time: 21:29
 */

namespace utils;

/**
 * 签名校验
 * Class Sign
 * @package utils
 */
class Sign
{
    private $appId = "2jOlqkesGGeJJwMx";
    private $appKey = "wfEj1kXLdKjCV6rla6Rfasd";

    //创建sign
    public function makeSign($data)
    {
        ksort($data);
        $string = $this->toUrlParams($data);
        $string = $string . "&key=" . $this->appKey;
        $string = md5($string);
        $result = strtolower($string);
        return $result;
    }

    //检验sign是否正确
    public function verifySign($data)
    {
        //check sign
        if (!isset($data['sign']) || !$data['sign']) {
            return ['code' => 1, 'msg' => '发送的数据签名sign不存在'];
        }

        //check sign
        if (!isset($data['appid']) || !$data['appid']) {
            return ['code' => 1, 'msg' => '发送的应用参数appid不存在'];
        }

        if ($data['appid'] != $this->appId) {
            return ['code' => 1, 'msg' => '发送的应用参数appid错误'];
        }

        //check sign
        if (!isset($data['nonce']) || !$data['nonce']) {
            return ['code' => 1, 'msg' => '发送的应用参数nonce不存在'];
        }

        //check timestamp
        if (!isset($data['timestamp']) || !$data['timestamp']) {
            return ['code' => 1, 'msg' => '发送的数据参数timestamp不合法'];
        }

        // 验证请求, 10分钟失效
        if (time() - $data['timestamp'] > 600) {
            return ['code' => 1, 'msg' => '验证超时timestamp请重新发送请求'];
        }

        $clientSign = $data['sign'];
        unset($data['sign']);
        $serverSign = $this->makeSign($data);
        if ($clientSign == $serverSign) {
            return ['code' => 0, 'msg' => '验证通过'];
        } else {
            return ['code' => 1, 'msg' => '签名校验失败'];
        }
    }

    //生成url字符串
    private function toUrlParams($values)
    {
        $buff = "";
        foreach ($values as $k => $v) {
            if ($k != "sign" && !is_array($v)) {
                $buff .= $k . "=" . $v . "&";
            }
        }
        $buff = trim($buff, "&");
        return $buff;
    }
}

使用实例,签名校验可以写在中间件拦截

<?php
/**
 * Created by PhpStorm.
 * User: Pasa吴
 * Date: 2023/1/2
 * Time: 21:29
 */

namespace app\api\controller;


use think\facade\Request;
use utils\Sign;

class Test
{
    public function sign(Request $request)
    {
        //接口签名校验
        $appid     = $request->header('appid', '');
        $nonce     = $request->header('nonce', '');
        $timestamp = $request->header('timestamp', '');
        $sign      = $request->header('sign', '');

        /* @var Sign $Sign */
        $Sign       = app(Sign::class);
        $verifySign = $Sign->verifySign(compact('appid', 'nonce', 'timestamp', 'sign'));
        if (isset($verifySign['code']) && $verifySign['code']) {
            throw new IllegalException();
        }
    }

}

前端vue代码

<div id="app">
</div>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="https://cdn.bootcss.com/blueimp-md5/2.10.0/js/md5.min.js"></script>
<script type="text/javascript">
    new Vue({
        el: '#app',
        data() {
            return {
                info: null
            }
        },
        create(){
        },
        methods: {
            getSign: function(param,key) {
                let str = "";
                for(var idx in param) {
                    let one = idx+"="+param[idx];
                    if (str == "") {
                        str = one;
                    } else {
                        str = str+"&"+one;
                    }
                }
                str = str+"&key="+key;
                //console.log("before md5:"+str);
                let md5str = md5(str);
                return md5str;
            }
        },
        mounted() {
            let appid = "2jOlqkesGGeJJwMx";
            let appkey = "wfEj1kXLdKjCV6rla6Rfasd";
            let timestamp = parseInt((new Date()).getTime()/1000);
            let nonce = Math.floor(Math.random()*8999)+1000;
            let param = {
                appid:appid,
                nonce:nonce,
                timestamp:timestamp,
            }
            let sign = this.getSign(param,appkey);
            param.sign = sign;
            console.log(param);

            const config = {
                headers: {
                    appid: param.appid,
                    nonce: param.nonce,
                    timestamp: param.timestamp,
                    sign:param.sign,
                }
            };

            axios
                .post('https://www.baidu.com/api/Test/sign',[],config)
                .then(response => (this.info = response))
                .catch(function (error) { // 请求失败处理
                    console.log(error);
                });
        }
    })
</script>

Pasa吴技术博客
请先登录后发表评论
  • latest comments
  • 总共0条评论