前言
上次說完了通用介面加密驗證,這次來說一下非通用介面的驗證,在說之前我們來看一下移動端需要通過非通用介面時的表欄位。
一.表欄位
id 主鍵ID
uid 使用者ID
deviceid 裝置唯一識別碼
token 加密使用欄位(可以使用UUID1)
token_time token過期時間
二、非通用介面
回憶下這段程式碼,來看看非通用方法裡做了什麼
private function verify($request)
{
if($request->path()=='login'){
// 通用方法
return self::$verify->common($request);
}else{
// 非通用方法
return self::$verify->proprietary($request);
}
return false;
}
在proprietary
裡都做了一下操作
public function proprietary($request)
{
if($request->all()){
$data = $request->all();
// 時間驗證
$ckTime = $this->checkTime($data['time']);
if(!$ckTime) return 'SN002';
// 因為是非通用介面,這裡的id,就需要是使用者表裡的ID,
if(!isset($data['id'])) return "SN004";
// 根據版本設計不同的驗證
switch ($data['version']){
case $data['version'] >'1.4' && $data['version']<'2.0':
$temp = $this->checkProprietary_v1($request);
break;
default:
$temp = $this->checkProprietary_v2($request);
break;
}
if($temp){
switch ($temp){
case 'SN007': // 使用者不存在
return 'SN007';
break;
case 'SN008': // 其他裝置登入
return 'SN008';
break;
case 'SN009': // token 過期
return 'SN009';
break;
default: // 驗證成功
return 'SN200';
break;
}
}
return "SN005";
}
return false;
}
在上邊操作中,把請求傳送到了checkProprietary_v1方法中,在看這個方法之前先看一下user方法
//這裡根據key從快取中讀取資料,如果不存在就去資料庫中獲取資料,然後存在快取中
public function user($id)
{
$key='USER:MESSAGE:'.$id;
if(!\Redis::exists($key)){
$userJson = Common::curl('/getToken',['id'=>$id],1);
$user = json_decode($userJson,1);
if($user['ServerNo'] == 'SN200'){
\Redis::hMset($key,$user['ResultData']);
return $user['ResultData'];
}else{
return false;
}
}
return \Redis::hGetall($key);
}
現在再看checkProprietary_v1方法
private function checkProprietary_v1($request)
{
$data = $request->all();
$path = $request->path();
$param = $data['param'];
$id = $data['id'];
$signature = $data['signatures'];
$time = $data['time'];
$deviceid = $data['deviceid'];
$user = $this->user($id);
if(!$user) return 'SN007'; // 使用者不存在
$tokentime = $user['token_time']; //獲取token的過期時間
if($deviceid != $user['deviceid']){
return 'SN008'; // 識別碼不同 拋其他裝置登入 並重新登入
}
if($time > $tokentime){
return 'SN009'; // token超時 重新登入
}
$token = $user['token']; // 獲取使用者的token
//需注意生成的token為32位的字串
$hashs = [
[1,2,23,28,23,45],
[6,8,19,25,30,31],
[0,25,31,3,4,8],
[2,31,0,9,3,17],
[29,2,1,17,21,26],
[10,5,18,9,2,3],
[5,10,15,17,18,22],
[8,20,22,37,19,21],
// 可以繼續定義陣列
];
$strs =substr($token,4,1);
$strs.=substr($token,5,1);
$strs.=substr($token,9,1);
$code = hexdec($strs);
$str1 = $code%8;
$arr =$hashs["$str1"];
$m = null;
foreach($arr as $v){
$m.= substr($token,$v,1);
}
$str = md5($path.$time.$id.$param.$m);
if($signature == $str){
return 'SN200';
}else{
return false;
}
}
解釋:
使用者每次登陸時,賬號密碼驗證通過將以下欄位存入資料庫,如UID存在則進行修改
uid // 使用者ID 唯一
deviceid // 裝置唯一識別碼,每次登陸時都需獲取一次
token // 每次登陸都需要重新生成一條
token_time // 需改變 當前時間+希望保持的時間
注意點:
1.登陸成功後,一定要報token返回給移動端
2.在移動端也要儲存$hashs陣列,並使用一樣的演算法
最後貼出一段根據狀態碼返回資訊提示的程式碼
public function handle($request, Closure $next)
{
$time = time();
switch($this->verify($request))
{
case "SN200":
$temp = $next($request);
// 封裝
return $temp;
break;
case "SN001":
return response()->json(['serverTime'=>$time,'ServerNo'=>'SN001','ResultData'=>'Server internal error!']);
break;
case "SN002":
return response()->json(['serverTime'=>$time,'ServerNo'=>'SN002','ResultData'=>'Request timeout!']);
break;
case "SN003":
return response()->json(['serverTime'=>$time,'ServerNo'=>'SN003','ResultData'=>'Version number exception!']);
break;
case "SN004":
return response()->json(['serverTime'=>$time,'ServerNo'=>'SN004','ResultData'=>'Global user ID can not be null!']);
break;
case "SN005":
return response()->json(['serverTime'=>$time,'ServerNo'=>'SN005','ResultData'=>'Signature error!']);
break;
case "SN007":
return response()->json(['serverTime'=>$time,'ServerNo'=>'SN007','ResultData'=>'user not!']);
break;
case "SN008":
return response()->json(['serverTime'=>$time,'ServerNo'=>'SN008','ResultData'=>'Other devices login!']);
break;
case "SN009":
return response()->json(['serverTime'=>$time,'ServerNo'=>'SN009','ResultData'=>'token time out!']);
break;
default:
return response()->json(['serverTime'=>$time,'ServerNo'=>'SN006','ResultData'=>'No access!']);
}
}