接口 和 h5 的数据处理 (加密 和 验签 和 鉴权)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_41782053/article/details/80399084

首先判断配置文件配置是否加密

    #签名参数
    'mcrypt'=>[
        'is_open'=> true,  #是否开启加密 默认true
        'key'    => 'mcrypt',
        'iv'     => '00000000'
    ],
    #允许调用的接口 app_id 和 app_secret
    'api_allow_access'=>[
        '123456' => 'asdfghjkl',
    ],

如果is_open = true
把登录或其他提交的数据通过客户端加密 把app_id 加入api_param,app_secret拼接到json后面并MD5排列

    #生成客户端的签名
    private function _makeClientSign(&$api_param)
    {
        $api_auth = Yii::$app->params['API_AUTH'];

        #加上接口鉴权
        $api_param['app_id'] = $api_auth['api_id'];

        #排序
        ksort($api_param);

        #转json
        $json = json_encode($api_param);

        #json 串 + api_secret
        $json = $json.$api_auth['api_secret'];

        return md5($json);
    }

通过yii框架的param配置文件配置要跳转的路径

    #api 接口域名
    'url'=>[
        #主域名
        'domain' => '',
        #接口的域名
        'api_host' => '',
        #接口的列表
        'api_list' => [
            #获取图片验证码的url
            'getVcodeUrl' => '',
            #登录接口
            'login' => '',
            #商品列表接口
            'goodsList' => '',
            #商品详情
            'goodsDetial' => '',
            #购物车session列表接口
            'shopCartList' => '',
            #获取购物车列表对应的商品信息
            'getShopInfo' => '',
        ]
    ],

//发送api请求

    public function sendApiRequest( $conf_name ,$api_param = [])
    {
        $api_url = $this->buildApiUrl($conf_name);

        $mcrypt = Yii::$app->params['mcrypt'];

        #验签
        $api_des_data['sign'] = $this->_makeClientSign($api_param);

        #对称加密
        if($mcrypt['is_open'] == true){
            if(!empty($api_param)){
                $api_des_data['data'] = Des::encode(json_encode($api_param),$mcrypt['key'],$mcrypt['iv']);
            }else{
                $api_des_data['data'] = [];
            }
        }else{
            $api_des_data['data'] = $api_param;
        }

        return $this->CurlPost($api_url , $api_des_data);
    }

然后通过curlPOST 提交到api页面

在tp5框架也同理配置

//是否开启加密
    'mcrypt'=>[
        'is_open'=> true,  #是否开启加密 默认true
        'key'    => 'mcrypt',
        'iv'     => '00000000'
    ],

然后建立构造方法initlize()

并直接判断配置项是否开启签名验证
如果开启验证就同样手法进行验证
验证通过则进行下一步 否则提示验签失败

其主要作用是防止信息被篡改;如果某个控制器方法不需要验签操作可以在api/common iniyialize 中加一个public属性

# 注 不需要验证签名的接口  TODO 必须小写
public $not_check_sign =[
    'publics/getvcodeurl'
];

 public function _initialize()
{
    parent::_initialize();
    $api_des = config('api.mcrypt');
    $data = request()->post('data');

    if($api_des['is_open'] == true){
        if(!empty($data)){
            $data_arr = json_decode(Des::decode($data,$api_des['key'],$api_des['iv']),true);
        }else{
            $data_arr = [];
        }
        $this->_data = $data_arr;
    }else{
        $this->_data = request()->post();
    }
    #签名
    $clientSign = request()->post('sign');

    #判断接口是否需要验签
    $this->_inspectionSign($this->_data,$clientSign);

}

// 验签

    private function _inspectionSign($data,$clientSign)
{
    $controller = request()->controller();
    $action = request()->action();

    $url = $controller.'/'.$action;

    if(in_array(strtolower($url),$this->not_check_sign)){
        $serverSign = $this->_makeServerSign($data);

        if($clientSign != $serverSign){
            $this->error('数据验签失败');
        }
    }
}

// 生成服务器的签名

   private function _makeServerSign($data)
{
    #排序
    ksort($data);

    #取出api_id
    if(empty($data['app_id'])){
        $this->error('鉴权失败');
    }

    # 根据app_id 取出对应的 app_secret
    $api_allow_access = config('api.api_allow_access');

    #如果传过来的app_id 不存在 提示鉴权失败   函数:array_key_exisets() 检查给定的键名或索引是否存在于数组中
    if(!array_key_exists($data['app_id'],$api_allow_access)){
        $this->error('鉴权失败');
    }

    #转json
    $json = json_encode($data);
    return md5($json.$api_allow_access[$data['app_id']]);
}


**注意** :两个配置文件的iv必须相同,否则会出现验签失败;

tp5 Des类如下

    <?php
    namespace Des;
    /**
     * des Helper Class
     */
    class Des
    {

        /**
         * DES加密 (需要打开php.ini的extension=php_mcrypt.dll)
         * @param string $input
         * @param string $key
         * @return string
         */
        public static function encode($input, $key, $iv)
        {

            //填充算法 PKCS7
            $input = DES::addPKCS7Padding($input);

            //打开算法和模式对应的模块  加密算法 3DES 加密模式 CBC
            $td = mcrypt_module_open(MCRYPT_3DES, '', 'cbc', '');

            //设置加密的key 以及初始化向量
            mcrypt_generic_init($td, $key, $iv);

            //加密
            $encrypted_data = mcrypt_generic($td, $input);


            //对加密模块进行清理工作
            mcrypt_generic_deinit($td);

            //关闭加密模块
            mcrypt_module_close($td);


    //        var_dump(base64_encode($encrypted_data) );exit;

            //加加密的数据进行base64编码
            $encode = trim(chop(base64_encode($encrypted_data)));

            return $encode;
        }

        /**
         * DES解密
         * @param string $input
         * @param string $key
         * @return string
         */
        public static function decode($input, $key, $iv)
        {
            //反编码
            $input = trim(chop(base64_decode($input)));

            //打开算法和模式对应的模块  加密算法 3DES 加密模式 CBC
            $td = mcrypt_module_open(MCRYPT_3DES, '', 'cbc', '');

            //设置加密的key 以及初始化向量
            mcrypt_generic_init($td, $key, $iv);

            //解密的数据
            $decrypted_data = mdecrypt_generic($td, $input);

            //对加密模块进行清理工作
            mcrypt_generic_deinit($td);

            //关闭加密模块
            mcrypt_module_close($td);

            //去除 PKCS7 填充
            $decrypted_data = DES::stripPKSC7Padding($decrypted_data);

            return $decrypted_data;
        }

        //PKCS7填充
        private static function addPKCS7Padding($source)
        {
            //获得加密算法的分组大小 8
            $block = mcrypt_get_block_size(MCRYPT_3DES, 'cbc');

            //计算要填充的长度
            $pad = $block - (strlen($source) % $block);

            //填充字符串
            if ($pad <= $block) {

                //chr — 返回指定的字符 ASCII
                $char = chr($pad);

                //填充字符串
                $source .= str_repeat($char, $pad);
            }
            return $source;
        }

        //去除PKCS7的填充
        private static function stripPKSC7Padding($source)
        {
            //获得加密算法的分组大小 8
            $block = mcrypt_get_block_size(MCRYPT_3DES, 'cbc');

            $char = substr($source, -1, 1);

            //返回字符的 ASCII 码值
            $num = ord($char);

            if ($num > 8) {
                return $source;
            }

            $len = strlen($source);
            for ($i = $len - 1; $i >= $len - $num; $i--) {
                if (ord(substr($source, $i, 1)) != $num) {
                    return $source;
                }

            }
            $source = substr($source, 0, -$num);

            return $source;
        }
    }
展开阅读全文

没有更多推荐了,返回首页