123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- <?php namespace App\Http\Controllers\Api;
- use App\Exceptions\Api\VerifySignException;
- use App\Exceptions\Api\LoginException;
- use App\Facades\Servers\Encrypts\AccessToken;
- use App\Facades\Servers\Encrypts\ApiSign;
- use App\Http\Controllers\Controller;
- use App\Models\Custom;
- /**
- * 接口控制器
- *
- * @author 刘相欣
- *
- * */
- class Api extends Controller{
- /**
- * 登录验证
- *
- * @return Int $authcode 登录信息
- *
- */
- public function checkLogin($authcode=''){
- // 默认接参
- $authcode = $authcode ? $authcode : request('authcode','');
- // 如果没有有登录信息
- if( !$authcode ) throw new LoginException("please_login");
- // 解码
- $decode = AccessToken::decode($authcode);
- // 错误返回
- if( isset($decode['error']) ) throw new LoginException("login_error");
- // 如果没有过期时间,过期处理
- if( empty($decode['exp']) ) throw new LoginException("login_exprie");
- // 如果过期,过期处理
- if( $decode['exp'] <= time() ) throw new LoginException("login_exprie");
- // 从缓存获取登录数据
- $memAuthcode = (new Custom())->getLoginAuthCodeByUid($decode['sub']);
- // 不存在登录信息,提示失败
- if( !$memAuthcode ) throw new LoginException("login_miss");
- // 如果是32位的话
- if( strlen($memAuthcode) == 32 ) $authcode = md5($authcode);
- // 如果存在登录数据,并且不是当前用户的缓存登录,提示失败
- if( $authcode != $memAuthcode ) throw new LoginException("login_miss");
- // 返回用户ID
- return $decode['sub'];
- }
- /**
- * 登录验证
- *
- * @return Int 用户ID
- *
- */
- public function getUid($authcode=''){
- // 默认接参
- $authcode = $authcode ? $authcode : request('authcode','');
- // 如果没有有登录信息
- if( !$authcode ) return 0;
- // 尝试执行
- try {
- // 解码
- $decode = AccessToken::decode($authcode);
- // 错误返回
- if( isset($decode['error']) ) return 0;
- // 如果没有过期时间,过期处理
- if( empty($decode['exp']) ) return 0;
- // 如果过期,过期处理
- if( $decode['exp'] <= time() ) return 0;
- // 返回用户ID
- return $decode['sub'];
- } catch (\Throwable $th) {
- // 返回0
- return 0;
- }
- }
- /**
- * 接口验签
- *
- * @param [Array] $data 参与验证的参数
- *
- *
- * */
- public function verify_sign($data=[]){
- // 获取参数
- $data = $data ? $data : request()->all();
- // 没有签名
- if( empty($data['sign']) ) throw new VerifySignException('sign_miss');
- // 没有签名
- if( empty($data['appid']) ) throw new VerifySignException('appid_miss');
- // 传了key
- if( !empty($data['key']) ) throw new VerifySignException('appkey_no_allow');
- // 没有请求时间
- if( empty($data['timestamp']) ) throw new VerifySignException('sign_timeout');
- // 请求过期
- if( abs(time() -$data['timestamp'] ) > 86400 ) throw new VerifySignException('sign_timeout');
- // 已使用过的签名不允许二次使用
- $this->checkSignUsed($data['sign']);
- // 从配置读取接口验签应用数据
- $verify = ['2DEA6A19BDCA383B'=>'FD6F87E89EABAF1063A849D971B68618'];
- // 是否有对应的appid
- if( !isset($verify[$data['appid']]) ) throw new VerifySignException('appid_nofund');
- // appkey
- $appkey = $verify[$data['appid']];
- // 获得签名参数数据
- $sign = $data['sign'];
- // 删除传入签名参数
- unset($data['sign']);
- // 删除上传文件的字段
- if( isset($data['file'])) unset($data['file']);
- // 键名字典排序
- ksort($data);
- // 空字符串
- $param = '';
- // 循环参数对象,拼接url字符串
- foreach ( $data as $key => $value ) {
- // 如果键值为空(空字符串 空数组 空集合 空对象 字符串0 数字0 NULL FALSE),此参数省略;另 '000' 这类0组成的字符串 不为空
- if( strtolower($value) == 'false' || strtolower($value) == 'null' || empty($value) || ( is_numeric($value) && $value == 0 && substr_count($value,'.') == 1 ) ) continue;
- // 判断键值是否是数组,对象 ,如果是的话,键值转json字符串
- if( is_array( $value ) || is_object($value) ) $value = json_encode($value,JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE);
- // 如果键值为真则 键值转md5加密(此处小写) 为假则直接拼接,0特殊处理
- $param .= '&'.$key.'='.$value;
- }
- // 转码
- $param = ltrim($param,'&');
- // 解码
- $param = rawurldecode($param);
- // 拼接私钥数据
- $param .= '&key='.$appkey;
- // 比对签名,数据加密(MD5后转大写),$param.'=>'.strtoupper(md5($param)).'=>'.$sign
- if( strtoupper(md5($param)) != $sign) throw new VerifySignException('sign_error');
- // 验签通过
- return ['success'=>'验签成功'];
- }
- /**
- * 判断签名是否已用
- *
- * @param [Array] $data 参与验证的参数
- *
- *
- * */
- public function checkSignUsed($sign='') {
- // 获取签名
- $is_used = cache('ApiSign:'.$sign);
- // 如果签名已用
- if( $is_used ) throw new VerifySignException('sign_used');
- // 存储已经验证过的签名
- cache(['ApiSign:'.$sign=>$sign],60);
- // 成功返回
- return ['success'=>'签名可用'];
- }
- /**
- * 接口验签
- *
- * @param Array $data 参与验证的参数
- *
- *
- * */
- public function sign($data) {
- // 返回加密结果
- return ApiSign::encode($data);
- }
- }
|