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 = json_decode(config('api_verify'),TRUE); // 是否有对应的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); } }