首先判断配置文件配置是否加密
#签名参数
'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;
}
}