1.使用composet安装JWT
composer require firebase/php-jwt
安装成功后会在项目根目录\vendor下生成firebase文件夹,里面就是JWT的相关文件
2.在项目根目录\extend\Tools\JWT新建JWTAuth.php类封装JWT,分别封装getAdminToken()生成Token方法和checkAdminToken()校验token方法,代码如下:
<?php
namespace Tools\JWT;
use Firebase\JWT\BeforeValidException;
use Firebase\JWT\ExpiredException;
use Firebase\JWT\JWT;
use Firebase\JWT\SignatureInvalidException;
/**
* 封装JWT身份认证类
*/
class JWTAuth
{
/**
* 封装管理员Token生成参数
* @param int $id 登录的用户id
* @param $mobile 登录用户手机号码
*/
public static function getAdminToken(int $id,$mobile){
//把配置文件config/app.php里面自定义常量JWTAuth_key当作盐值
$key = config('app.JWTAuth_key');
//定义token生成信息项,并赋值给$tokenmsg
$tokenmsg = array(
"iss" => config('app.JWTAuth_iss'),//签发机构,比如爱兔网
//"aud" => $id,//接收人,也就是发给谁
"iat" => time(),//签发时间,当前时间
"nbf" => time()+3,//生效时间,在生成时间后一点点
'exp' => time()+10800,//过期时间,三个小时
'data'=> ['mobile'=>$mobile,'uid'=>$id]//自定义信息
);
//利用JWT里面的encode()方法生成token
$token = JWT::encode($tokenmsg,$key,'HS256');//最后一个参数是转码方式定义
return $token;
}
/**
* 封装Toekn检验方法
* @param string $token
* @return array
*/
public static function checkAdminToken(string $token){
//调用$key
$key = config('app.JWTAuth_key');
//校验token
try {
//延长有效期1分钟
JWT::$leeway = 60;
//对token解码,得到的一个对象,所以直接转成数组
$data = (array)JWT::decode($token,$key,array('HS256'));
//获取token里面的相关信息并赋值给数据集
$result['data'] = $data['data'];
//定义Result变量的status字段
$result['status'] = 10001;
//验证通过后返回$result数据集
return $result;
//如果验证失败,catch以下错误
}catch (SignatureInvalidException $exception){
//定义result数据集状态码status和data的默认值
$result['status'] = 10002;
$result['data'] = '验证失败!请重新登录';
return $result;
}catch (BeforeValidException $exception){
//定义result数据集状态码status和data的默认值
$result['status'] = 10003;
$result['data'] = 'token未生效,请稍后!';
return $result;
}catch (ExpiredException $exception){
//定义result数据集状态码status和data的默认值
$result['status'] = 10004;
$result['data'] = '登录过期,请重新登录!';
return $result;
}catch (\Exception $exception){
//定义result数据集状态码status和data的默认值
$result['status'] = 10005;
$result['data'] = '未知错误,请重新登录!';
return $result;
}
}
}
3.登录成功后生成Token
//如果用户正常,表示登录成功,利用JWT生成AdminToken
$token = JWTAuth::getAdminToken($admin['id'],$admin['mobile']);
return $this->ReturnApi(['result'=>true,'token'=>$token],'登录成功!',200);
4.中间件校验Token,新建登录判断中间件AdminCheckToken.php
<?php
declare (strict_types = 1);
namespace app\middleware;
use app\controller\Common;
use Tools\JWT\JWTAuth;
class AdminCheckLogin extends Common
{
/**
* 管理员登录处理请求,把Admincheck中间件添加到Admin路由中,只有通过中间件才能访问Admin api接口
*
* @param \think\Request $request 客户端传过来的token
* @param \Closure $next 回调函数闭包,也就是验证token后再通过$next回调函数把数据传递到下一步
* @return Response 必须返回Respone对象
*/
public function handle($request, \Closure $next)
{
//获取前端header请求信息并把token信息转在字符串
$token = (string)$request->header('Authorization');
if (empty($token)){
return $this->ReturnApi([],'请先登录!');
}
//调用JWTAuth里面的checkAdminToken()方法对token解码
$result = JWTAuth::checkAdminToken($token);
//result得到包含有status/data字段的数据集
if ($result['status'] !==10001){
//如果status 不等于10001,验证失败,返回错误提示
return $this->ReturnApi($result,'登录错误,请查看错误信息!');
}else{
//否则验证通过,把result里面data数据传给$request
//经过测试,数据并不能传到¥request的header里面,也不知道怎么调用,很是烦躁
$request->loginMsg = $result['data'];
//执行下一步代码
return $next($request);
}
}
}
5.使用路由中间件拦截对admin资源的操作,也就是必须登录才能访问admin有关的的操作
//admin api资源路由
Route::resource('admin','Admin')->middleware(\app\middleware\AdminCheckLogin::class);
6.登录成功生成Token
7.无Token时访问admin资源失败
8.Token错误时访问admin资源失败
?9.Token过期时访问失败
?
10.Token没有问题时访问成功!
?
?
?
|