移动端后台开发 (加密验证--非通用接口篇)
前言
上次说完了通用接口加密验证,这次来说一下非通用接口的验证,在说之前我们来看一下移动端需要通过非通用接口时的表字段。
一.表字段
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!']);
}
}
本作品采用《CC 协议》,转载必须注明作者和本文链接
Laravel内置了
Ramsey\Uuid\Uuid
类,不用自己写代码生成……后面
case
里的return
后继续接break
,看的有点尴尬。Uuid的文档介绍在哪一部分