PHP-ThinkPHP5.1实现sign校验API
本文最后更新于:a few seconds ago
ThinkPHP5.1实现sign校验API
本文适合有ThinkPHP经验的同学。
但是这个设计是根据用户登录产生的token加静态key作为解密的密钥,token过期时间为7200秒,增加了解密难度。
我直接写流程,加密是aes,具体往下翻,有错误请联系我😁
如果您刚从5.0升级到5.1
官方的文档写得很详细,ThinkPHP.5.1升级指导 。
1.建立sign的配置文件
进入config目录,创建aes.php,如下。(ps:在5.1版本需要在config目录配置)
return [
'aeskey'=>'这是你的key',//aes加密的密钥 客户端和服务端一致
'app_sign_time'=>7200,//sign失效时间,微信也是这时间
'app_sign_cache_time'=>20,//sign缓存的有效时间
];
当你需要使用的时候这样用
config('aes.app_sign_cache_time');
2.建立BaseController.php,这个是所有控制器的父类,继承Controller类
BaseController代码如下
/**
* @var string
*/
private $headers = '';
/**--初始化的方法 其他接口类只需要继承这个BaseController类 不需要再继承Controller
* @throws Exception
*/
public function initialize() {
$this->checkRequest();
/* } catch (Exception $e) {
return [
'code'=>1,
'message'=>$e
];
}*/
}
/** --验证数据是否合法 检查每次请求
* @throws Exception
*/
public function checkRequest(){
//首先获取header所有参数
$headers = request()->header();
//进行参数校验
if(empty($headers['sign'])){
throw new Exception('sign不存在!',1);
}
//如果sign校验不能通过
if(!IAuth::checkSignPass($headers)){
throw new Exception('sign校验失败失败!',1);
}
//sign做唯一性处理 写入Cache缓存
Cache::set($headers['sign'],1,config('aes.app_sign_cache_time'));
//赋值给类的属性
$this->headers = $headers;
}
3.创建Aes.php
在application/api/common/lib/Aes.php 创建文件,实际位置看您的情况。
代码如下
class Aes
{
private $key = null;
private $iv = null;
/**
*
* @param $key --密钥
* @return String
*/
public function __construct() {
$this->key =Cache::get('token').config('aes.aeskey');两者拼接
$this->key = hash('sha256', $this->key, true);
$this->iv = substr($this->key, 0, 16);
}
public function encrypt($input)
{
$data = openssl_encrypt($input, 'AES-256-CBC', $this->key, OPENSSL_RAW_DATA, $this->iv);
$data = base64_encode($data);
return $data;
}
public function decrypt($input)
{
$decrypted = openssl_decrypt(base64_decode($input), 'AES-256-CBC', $this->key, OPENSSL_RAW_DATA, $this->iv);
return $decrypted;
}
//增加当前时间
private function dataFiller($input){
return $input.'&time='.time();
}
}
4.创建验证授权验证规则方法
我是创建在application/api/common/lib/IAuth.php。
您可以创建在应用公共文件common下比较方便。
代码如下
/**
* @param array --检验sign是否能通过,具体规则可以自己与前端商量
* @return boolean
*/
public static function checkSignPass($data){
//解密
$str = (new Aes())->decrypt($data['sign']);
//如果解密之后为空
if(empty($str)){
return false;
}
//将$str解析成多个变量
parse_str($str,$arr);
//判断是否在有效时间内
if(time()-ceil($arr['time'] ) > config('aes.app_sign_time')){
return false;
}
//唯一性判定 如果存在 返回false
$echo = Cache::get($data['sign']);
if($echo){
return false;
}
return true;
}
这样就欧啦!
前端可以在拦截器里写加密参数的方法,所有发送的参数加上时间搓,加密后再发送。
记得前后端的密钥是一样的哦。
经过api的参数都会和时间一起被校验。
自我测试
1. BaseController的以下代码注释掉,因为我们要自我加密
$this->checkRequest();
2. 先登录一下让服务端记录token
3. 这是测试控制器里的方法,模拟前端加密
public function test($data,$time){
return (new Aes())->encrypt('data='.$data.'&time='.$time);
}
进行加密
4. 将加密获得的sign拿到header中
5.放开BaseController注释的代码
这样就能测试sign的有效性,和唯一性,api只能请求一次,第二次会抛出错误。
结束🐟
江南柳,叶小未成阴。 ——「望江南·江南柳」欧阳修
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!