项目需要向外部提供接口,供第三方网站调用,为了保证传输数据的安全性,给项目添加了签名认证的机制,过程大致如下:
一、由我们平台给第三方颁发一个appId和一个appSecret,appId用来传输,appSecret用来生成签名
二、第三方通过拼接appSecret生成签名sign,第三方将数据和appId一起传给我们平台
三、我们平台接收到数据后根据接收到的数据用同样的算法生成签名,通过比对签名确定来进行数据来源的有效性确认
部分代码如下:
一、appId和appSecret的存储表如下:
1 2 3 4 5 6 7 |
CREATE TABLE `encrypt` ( `id` int(11) NOT NULL AUTO_INCREMENT, `public_key` varchar(255) NOT NULL COMMENT '公钥', `screct_key` varchar(255) NOT NULL COMMENT '私钥', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4; |
二、生成appId和appSecret的方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
/** * 生成Key * @access public * @return array */ public static function makeKey() { $appId = strrev(microtime(true)*10000); $appSecret = md5(md5($appId.'awen').'awen'); $model = new \common\models\Encrypt(); $model->public_key = $appId; $model->screct_key = $appSecret; $model->save(); return [ 'appId' => $appId, 'appSecret' => $appSecret, ]; } |
三、签名生成方法:
- 对所有请求参数进行字典升序排列;
- 将以上排序后的参数表进行字符串连接,如key1value1key2value2key3value3...keyNvalueN;
- app secret作为后缀,对该字符串进行SHA-1计算,并转换成16进制编码;
- 转换为全大写形式后即获得签名串
具体签名生成与对比的代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
/** * 验证签名有效性 * @access public * @param array params 参数 * @param sting sign 签名 * @param sting appId * @return bool 验证结果 */ public static function checkSign($params,$sign,$appId) { //根据appId去数据库找到对应的appSecret $appSecret = self::getAppSecret($appId); // 1. 对加密数组进行字典排序 防止因为参数顺序不一致而导致下面拼接加密不同 ksort($params); // 2. 将Key和Value拼接 $str = ""; foreach ($params as $k => $v) { $str.= $k.$v; } //3. 通过sha1加密并转化为大写 //4. 大写获得签名 $restr=$str.$appSecret; $signRes = strtoupper(sha1($restr)); if($signRes == $sign){ return true; }else{ return false; } } |
四、在basecontroller中添加签名验证代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
/** * 验证签名 */ public function beforeAction($action) { $post = @file_get_contents('php://input'); \Yii::$app->log->targets[0]->logFile = \Yii::getAlias('@runtime').DIRECTORY_SEPARATOR.'logs'.DIRECTORY_SEPARATOR.'outside.log'; \Yii::trace('接受的数据为:'.$post); //解析成数组 $post = json_decode( $post, true ); $data = $post['data']; if(!$data){ $result = ['status'=> 0, 'message'=>'缺少参数data']; return \Yii::$app->response->data = $result; } $appId = $post['appId']; if(!$appId){ $result = ['status'=> 0, 'message'=>'缺少参数appId']; return \Yii::$app->response->data = $result; } parse_str($data,$params); $sign = $params['sign']; unset($params['sign']); $signCheck = Encrypt::checkSign($params,$sign,$appId); if($signCheck){ $result = ['status'=> 1, 'message'=>'数据正常','params'=>$params,'appId'=>$appId]; }else{ $result = ['status'=> 0, 'message'=>'签名错误','params'=>$params,'appId'=>$appId]; } return \Yii::$app->response->data = $result; } |
转载:https://blog.csdn.net/weixin_41981080/article/details/105522957

我的微信
把最实用的经验,分享给最需要的读者,希望每一位来访的朋友都能有所收获!