在实际工作中,使用PHP写api接口是经常做的,PHP写好接口后,前台就可以通过链接获取接口提供的数据,而返回的数据一般分为两种情况,xm
原理
需要生成签名的参数:
1、did:设备号,即app每个设备的唯一标识
2、version:版本信息,例:v1.0
3、time:时间戳,这里采用的是10位的时间戳
通过以上的字段,通过一定的算法生成sign,然后请求api时带上sign以及以上参数,然后服务器根据接收到的参数使用同样的方法生成sign与接收的sign进行比对,如果一致则通过。
算法
获取当前时间戳,为了保持app与服务器端时间一致,写了个时间获取的函数。
1、使用did,version,time组装成数组
2、键按照字典顺序排序
3、生成did=aaaa&time=123121&version=v1.0
4、进行加密
代码
代码如下:
Aes.php
namespace app\api\controller;
class Aes{
protected $key = 'aaaa13245';
/**
* AES-128-ECB加密
* @param [type] $data [description]
* @return [type] [description]
*/
public function encrypt($data){
$res = openssl_encrypt($data, 'AES-128-ECB', $this->key, OPENSSL_RAW_DATA);
return base64_encode($res);
}
/**
* AEC-128-ECB解密
* @param [type] $data [description]
* @return [type] [description]
*/
public function decrypt($data){
$res = base64_decode($data);
$res = openssl_decrypt($res, 'AES-128-ECB', $this->key, OPENSSL_RAW_DATA);
return $res;
}
}
Auth.php namespace app\api\controller;
use think\Exception;
class Auth{
protected $time = 10;
/**
* 验证签名
* @param [type] $data [description]
* @return [type] [description]
*/
public static function getSignature($data){
if(empty($data)){
return false;
}
ksort($data); //按字典顺序排序
$query = http_build_query($data);
//aes加密
return (new Aes())->encrypt($query);
}
/**
* 解密
* @param [type] $str [description]
* @return [type] [description]
*/
public static function checkSignature($str){
//解密aes
$data = (new Aes())->decrypt($str['sign']);
parse_str($data , $sign);
//验证设备号
if(empty($sign['did']) || !isset($sign['did']) || $str['did'] != $data['did']){
throw new Exception('sign验证失败');
}
//验证version
if(empty($sign['version']) || !isset($sign['version']) || $str['version'] != $data['version']){
throw new Exception('sign验证失败');
}
//验证 时间戳
if(empty($sign['time']) || !isset($sign['time']) || $str['time'] != $data['time']){
throw new Exception('sign验证失败');
}
$time = $sign['time'];
//非调试模式下验证sign过期时间
if(!config('app_debug')){
if((time()-$time) > $this->time ){ //已过期
throw new Exception('sign已过期');
}
}
return true;
}
}
common.php namespace app\api\controller;
use think\Exception;
class Common{
public $header;
public function _initialize(){
//检查sign
$this->checkSign();
}
/**
* 验证header是否合法
* @return [type] [description]
*/
protected function checkSign(){
//sign检查的3点,
//1:header头中的sign值是否存在,基础验证
//2:header头中的type是否存在,基础验证
//3:验证sign是否合法
$header = request()->header();
if(empty($header['sign']) || !isset($header['sign'])){
throw new Exception('sign验证失败');
}
if(empty($header['type']) || !isset($header['type']) || !in_array($header['type'],$type)){
throw new Exception('sign验证失败');
}
//验证sign是否合法
if(Auth::checkSignature($header)){
$this->header = $header;
}
}
/**
* 生成测试的sign
* @return [type] [description]
*/
public function getSign(){
//
//did:设备号
//version:版本号
//time:10位时间戳
$data = [
'did' => 'abdes12545',
'version' => 'v1.0',
'time' => Time::getTime()
];
return Auth::getSignature($data);
}
public function dSign(){
$str = 'YZ1mEk23PbRgpUbe6kny978JXcpKDB9qJXsQ0BaeWxG9xEbe/ko16Js8JC4gAMZs';
return Auth::checkSignature($str);
}
}
time.phpnamespace app\api\controller;
class Time{
/**
* 保证服务器端与app端时间一致
* @return [type] [description]
*/
public static function getTime(){
return time();
}
}
欢迎大家来我的博客http://crasphter.cn/article/19交流经验,共同进步 最佳答案
