接口 和 h5 的数据处理 (加密 和 验签 和 鉴权)详解程序员

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

    #签名参数 
    '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; 
        } 
    } 

原创文章,作者:Maggie-Hunter,如若转载,请注明出处:https://blog.ytso.com/6357.html

(0)
上一篇 2021年7月16日
下一篇 2021年7月16日

相关推荐

发表回复

登录后才能评论