关于接口安全 接口防刷 RSA 鉴权 签名 实现

关于接口安全 接口防刷 RSA 鉴权 签名 实现_第1张图片

直接贴代码了。客户端使用的YII框架,接口使用的TP5

 

客户端的公共Common   , 一个调接口的方法  

params['authentication']['app_secret'];

            //生成签名
            asort($param); //按照键值对关联数组进行升序排序
            $secret['sign'] = md5(json_encode($param));

            if($encrypt == 1){
                //公钥加密
                $secret['key'] = Rsa::encrypt(json_encode($param));
            }
        }else{
            $secret['sign']='';
        }

        //初始化curl
        $curl = curl_init();

        // 设置请求的路径  curlopt_url:
        curl_setopt($curl, CURLOPT_URL, $url);

        if( $is_post == 1 ){
            //设置POST提交
            curl_setopt($curl, CURLOPT_POST, 0 );
        }

        //显示输出结果  1代表 把接口返回的结果当作一个字符串处理
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

        // 设置请求超时时间
        curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);

        curl_setopt( $curl ,CURLOPT_SSL_VERIFYHOST , false );
        curl_setopt( $curl ,CURLOPT_SSL_VERIFYPEER , false );

        if( $is_post == 1 ){
            curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($secret));
        }
        //执行请求
        $data = $data_str = curl_exec($curl);

        //处理错误
        if ($error = curl_error($curl)) {
            $log_data = array(
                'url' => $url,
                'param' => $param,
                'error' => '' . $error . '',
            );

            var_dump($log_data);
            exit;
        }

        # 关闭CURL
        curl_close($curl);

        //json数据转换为数组
        $data = json_decode($data, true);
//        var_dump($data_str);exit;
        if (!is_array($data)) {
            $data = $data_str;
        }

        //解密回调数据

        #调用玩接口之后写一个日志
        $log = [
            'url'  => $url ,
            'param' => $param ,
            'response' => $data_str
        ];
        file_put_contents( __DIR__.'/wechat.log' , print_r( $log , true ) , 8 );

        //公钥解密
        $return_data = json_decode(Rsa::decrypt($data) , true);
        return $return_data;

    }

   
}

下面是接口的公共Common  

_checkRsa();
        #鉴权
        $this->authentication();
        #接口防刷
        $this->prevent_refresh();
        #验签
        $this->_checkSign();
    }

    //接口防刷
    private function prevent_refresh(){
        # 100s调用接口不能超过2次 如果超过限制 拉黑5s
        $limit = 2;
        $expire_time = 100;
        $error_time = 5;
        $time = time();

        $redis = new \Redis();
        $redis->open('132.232.101.24',6379);
        $redis->auth(123);
        $redis->select(12);
//        $redis->flushAll();
        $ip =  request()->ip();
        # 判断ip在黑名单里是否过期
        $sore_time = $redis->zScore('blacklist',$ip);
        if(($time-$error_time) < $sore_time){
            $this->error("调用接口过于频繁,请稍后再试");
        }else{
            $redis->zRem('blacklist',$ip);
        }

        # 判断是否有当前访问ip  如果没有存入redis记录储存时间  如果有记录自增次数
        $num = $redis->get($ip);
        if(!$num){
            $redis->incr($ip);
            $redis->expire($ip,$expire_time);
        }else{
            $redis->incr($ip);
        }

        //判断当前访问次数是否超过限制次数
        if((int)$num >$limit){
            $redis->zAdd('blacklist',$time,$ip);
            $this->error("访问接口过于频繁,请稍后再试");
        }

    }


    //数据解密
    private function _checkRsa(){
        if(Config::get('open_rsa') == true){
            $data = request()->post('key');
            self::$secret = json_decode(rsakey::decrypt($data), true);  //私钥解密
        }else{
            self::$secret = Request()->post('key');
        }
    }


    //鉴权
    private function authentication(){
        $data = self::$secret;
        $app_scret = Config::get('authentication.app_secret');
        if($data['app_secret'] != $app_scret){
            $this->error("您没有权限调用此接口");
        }

    }


    //验证sign
    private function _checkSign(){
        if(Request()->isPost()){
            if(empty( Request()->post('sign') )){
                $this->error("验签失败");
            }

            asort(self::$secret);//按照键值对关联数组进行升序排序
            $data = md5( json_encode( self::$secret ) );
            $private_data =  Request()->post('sign') ;

            if($data != $private_data){
                $this->error("验签失败2");
            }
        }
    }


    //正确提示
    public function success($msg , $data=[]){
        $arr = [ 'code' => 1000 , 'msg' => "$msg", 'data' => $data];
        $return_data = rsakey::encrypt( json_encode($arr));  //私钥加密
        echo $return_data;
        exit;
    }


    //错误提示
    public function error($msg , $data=[]){
        $arr = [ 'code' => 1 , 'msg' => "$msg" , 'data' => $data];
        $return_data = rsakey::encrypt(json_encode($arr));  //私钥加密
        echo $return_data;
        exit;
    }


}

下面是RSA类文件

首先  客户端 公钥加密 公钥解密的类方法

params['secret_key']['public_key'];
    }

    //公钥加密
    public static function encrypt($data){
        self::__init();
        $data_len = strlen($data);
        $i = 0;
        $encode = '';
        while($i < $data_len){
            $encode .= self::opensslEncode(substr($data,$i,117));
            $i += 117;
        }
        return $encode;
    }

    //公钥加密
    private static function opensslEncode($data){
        if(openssl_public_encrypt($data,$encrypted,self::$pubkey))
            $data = base64_encode($encrypted);
        else
            throw  new Exception('Unable to encrypt data.Perhaps it is bigger than the key size?');
        return $data;
    }


    //公钥解密
    public static function decrypt($data){
        self::__init();
        $data_len = strlen($data);
        $i = 0;
        $decode = '';
        while($i < $data_len){
            $decode .= self::opensslDecode(substr($data,$i,172));
            $i +=172;
        }
        return $decode;
    }

    //公钥解密
    private static function opensslDecode($data){
        if(openssl_public_decrypt(base64_decode($data),$decrype,self::$pubkey)){
            $data = $decrype;
        }else{
            $data ='';
        }

        return $data;
    }



}

?>

接口 私钥解密 私钥加密的类方法

关于 接口安全 实现思路及拓展

RSA:https://blog.csdn.net/DuTianTian_csdn/article/details/80832502

接口防刷:https://blog.csdn.net/DuTianTian_csdn/article/details/81277434

签名:https://blog.csdn.net/DuTianTian_csdn/article/details/81277438

你可能感兴趣的:(使用方法)