1.composer安装 jwt
composer require lcobucci/jwt 3.3
2.在extend/tools/jwt目录下创建Token.php文件
注意 extend目录下tools/jwt目录没有需要自己创建
<?php
namespace tools\jwt;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\ValidationData;
class Token
{
// createToken为生成token令牌的方法
public static function createToken($uid = null)
{
$signer = new Sha256();//加密规则
$time = time();//当前时间
$token = (new Builder())
->issuedBy('teacher')//签发人
->canOnlyBeUsedBy('student')//接收人
->identifiedBy('MarsLei', true) //标题id
->issuedAt($time)//发出令牌的时间
->canOnlyBeUsedAfter($time) //生效时间(即时生效)
->expiresAt($time + 3600) //过期时间
->with('uid', $uid) //用户id
->sign($signer, 'my') //签名
->getToken(); //得到token
return (string)$token;
}
//verifyToken 为验证token令牌的方法
public static function verifyToken($token=null){
//检测是否接收到了token
if(empty($token)){
return 0;
}
//转化为可以验证的token
$token = (new Parser())->parse((string) $token);
//验证基本设置
$data = new ValidationData();
$data->setIssuer('teacher');
$data->setAudience('student');
$data->setId('MarsLei');
if(!$token->validate($data)){
return 0;
}
//验证签名
$signer = new Sha256();
if(!$token->verify($signer, 'my')){
return 0;
}
//验证通过,返回用户id
return $token->getClaim('uid');
}
}
3.生成token 验证token的方法
一般我们在登录成功后将用户数据的id生成token令牌
//生成token
$token = Token::createToken($userInfo['id']); //生成token
//验证Token
$res = Token::verifyToken($token);
if (!$res) {
//验证失败
$this->error('token令牌失效', 'home/Login/login');
}
4.在controller目录下创建Base控制器
让你需要验证的控制器继承Base控制器
<?php
namespace app\home\controller;
use think\Cache;
use think\Controller;
use think\Request;
use think\Session;
use tools\jwt\Token;
class Base extends Controller
{
//将你控制器中不需要验证的方法写在此数组中即可不用token验证
protected $url = ['book/book',"book/type","book/detail"];
function __construct(Request $request = null)
{
$ip = request()->ip();//获取ip地址
$num = Cache::store('redis')->get($ip.'times');//获取请求次数
$lastTime =Cache::store('redis')->get($ip);//获取上次请求的时间
if(time()-$lastTime<60)
{
// echo $num;
if ($num >=5)//每分钟请求大于等于5次的时候限制请求
{
$res = [
'code' => 511,
'msg' => '操作过于频繁,'
];
echo json($res)->send();die;//返回信息阻止继续请求
}
}
if($num>=5){
Cache::store('redis')->handler()->del($ip.'times');//等待时间过期后清除单位时间请求次数
}
parent::__construct($request);
$route = strtolower(request()->controller().'/'.request()->action());//获取请求控制器和方法
if(!in_array($route,$this->url))//判断请求的控制器方法是否在数组中,没有则需要登录验证
{
$token = request()->param('token');
if (empty($token))
{
$this->fail('token不存在', 403);die;//fail()是封装好的方法
}
//令牌验证
$res = Token::verifyToken($token);
if (!$res)
{
$this->fail('token无效',500);die;
}
}
Cache::store('redis')->set($ip,time());//将同一ip地址的第一次请求时间存入缓存
Cache::store('redis')->inc($ip.'times');//请求次数存入Redis做自增
}
protected function response($code=200, $msg='success', $data=[])
{
$res = [
'code' => $code,
'msg' => $msg,
'data' => $data
];
//原生php写法
// echo json_encode($res, JSON_UNESCAPED_UNICODE);die;
//框架写法
json($res)->send();
}
/**
* 成功的响应
* @param array $data 返回数据
* @param int $code 错误码
* @param string $msg 错误信息
*/
protected function ok($data=[], $code=200, $msg='success')
{
$this->response($code, $msg, $data);
}
/**
* 失败的响应
* @param $msg 错误信息
* @param int $code 错误码
* @param array $data 返回数据
*/
protected function fail($msg, $code=500, $data=[])
{
$this->response($code, $msg, $data);
}
}