直接贴代码了。客户端使用的YII框架,接口使用的TP5
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;
}
}
_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;
}
}
首先 客户端 公钥加密 公钥解密的类方法
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