php jwt token刷新方案,laravel JWT自动刷新 自定义验证器

在前面的文章中,我们引入了JWT的验证方式,但是在前面并没有做过多的处理,只是用JWT生成了一个token,那么今天来就解决后续问题

为了保证用户信息的安全, 我们的生成的JWT不可能一直有效,我们在配置文件里边配置的有有效期,这里的单位是分钟

100b9348283889c1a53242c9673176b2.png

但是当我们用户一直在60分钟之内在操作,但是JWT过期后就需要用户重新登录,这样是不合理的,那么就需要对JWT生成的token进行刷新,从而可以达到用户一直有效请求

那么接下来我们就模拟一下用户的操作,来做个简单的实例

我们先自定义一个路由文件,用来存放我们自己路由

63b6754e796d19e3dd0c1e3c232d38ce.png

然后定义几个路由用来测试

25fde3452cde8e32a50ce7a8d43919ff.png

修改一下JWT失效的时间

86c9e8f25041ae2f67b06b1a5fa47efb.png

在jwt-auth的组件中过期校验是由Expiration中的 validatePayload来校验jwt的过期时间

4fb825bb66e8c649756ad259d52d0c11.png

然后这里进行修改一下,因为过期时间是1分钟不好测试,我们来把这个过期时间进行调整一下,调整为15秒就过期

34140df84cb70ee8490e0a719103cf4f.png

然后我们进行一下测试登录

79b2f82f66692e3d77e0f47719f7a662.png

等15秒后咱们来获取一下用户信息,这里现在会报出token已经过期

de8feaeaa2bfd8c57bc46e98ddd56d1a.png

其实这里存在的问题就已经很明显了,如果用户这个时候在正常的操作,但是我们的token这个时候给过期了,那么对用户的体验来说肯定是不好的,那么下来我们就来解决这个问题

这个时候我们可以在异常这里做一个这样的操作,那就是让他在时间过期后给她重置登录时时间,如果到了这个时间我们需要重置一下请求头的token数据,但这样是手动操作的

82d59c5c260537f79b3561fc5ab99e30.png

然后在刷新页面,就依然可以获取到用户信息,但是这样肯定是不行的,这样做只是为了显示这个效果而已,实际项目这样肯定不可以,token到期后,就直接跳到登录,这样肯定是不可以的

66021f1d928bad91bdb3b47373c4edf5.png

所以我们的token在无刷新界面的情况下就很有必要了

那么代码怎么写?

代码写在哪里呢?

如果说对于token的检测,最好是使用与中间件,因为它可以很方便的帮助由我做到对于api请求的token检测;也就是说代码会写在于中间件中

所以创建一个刷新token的中间件

那么中间件会有什么问题?

1.       它不确定是否用户有登入

2.       它不确定之前登入的用户是否退出了登入

3.       如果当前的token过期了那不就请求就失败了?怎么解决呢?

解决问题以及流程;

1.       可以通过判断token是否存在,如果存在就有登入没有就没有登入

2.       判断用户的登入状态是否为退出;

3.       判断是否token过期

4.       跟新请求头部

流程:

f37f412305c10bf49db44e11fdad6b3c.png

创建自定义JWT自动刷新的中间件

c13cb74005979127e02bf2c44907423d.png

这里是中间件里边的内容,参考地址:https://learnku.com/articles/7264/using-jwt-auth-to-implement-api-user-authentication-and-painless-refresh-access-token

<?phpnamespace App\Http\Middleware;use Auth;use Closure;use Tymon\JWTAuth\Exceptions\JWTException;use Tymon\JWTAuth\Http\Middleware\BaseMiddleware;use Tymon\JWTAuth\Exceptions\TokenExpiredException;use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;class RefreshJwtToken extends BaseMiddleware{public function handle($request, Closure $next){// 检查此次请求中是否带有 token,如果没有则抛出异常。$this->checkForToken($request);// 使用 try 包裹,以捕捉 token 过期所抛出的 TokenExpiredException 异常try {// 检测用户的登录状态,如果正常则通过if ($this->auth->parseToken()->authenticate()) {return $next($request);}throw new UnauthorizedHttpException('jwt-auth', '未登录');} catch (TokenExpiredException $exception) {// 此处捕获到了 token 过期所抛出的 TokenExpiredException 异常,我们在这里需要做的是刷新该用户的 token 并将它添加到响应头中try {// 刷新用户的 token$token = $this->auth->refresh();echo '
---statr-----
';echo $token;echo '
----end----
';// 使用一次性登录以保证此次请求的成功$sub = $this->auth->manager()->getPayloadFactory()->buildClaimsCollection()->toPlainArray()['sub'];auth('api')->onceUsingId($sub);} catch (JWTException $exception) {// 如果捕获到此异常,即代表 refresh 也过期了,// 用户无法刷新令牌,需要重新登录。throw new UnauthorizedHttpException('jwt-auth',$exception->getMessage());}}// 在响应头中返回新的 tokenreturn $this->setAuthenticationHeader($next($request), $token);}}

其实实际上需要的方法就是

$this->auth->parseToken()->authenticate()

校验用户的登入状态

$this->checkForToken($request)

校验是否存在token

setAuthenticationHeader()

向响应输出的时候设置刷新的token

$this->auth->refresh()

刷新token

模仿BaseMiddleware-> authenticate()的写法,不过注意那个方法中所抛出的异常并不是实际所需要的异常JWTException 包含了所有异常对于过期时间的异常也在这里,但是对于目前的情况最好是可以抛出TokenExpiredException 过期的异常;

其实最难的还是后面那个点,这是难点所在。这个点的解释最有从源码的角度解释会好;

$this->auth->manager()->getPayloadFactory()->buildClaimsCollection()->toPlainArray()['sub'];

获取jwt-token中的用户id

d36d921369f3c6dba646d2f86d138e6b.png

auth(‘api’)->onceUsingId();将改定的用户设置为登入;其实这一步就是把用户设置成为登录状态

ebb0b7b2dc9fb700e87aed2295b65764.png

然后进行测试

首先需要把上边创建的中间件注册到我们的路由中间件里边去

a6be1f0bca046b3df470d4681c64622d.png

然后修改路由

08b688f428cb258b31adc13267b37d52.png

把Expiration.php恢复,当令牌过期,让其抛出TokenExpiredException异常,让自定义的中间件捕获后在来生成令牌

568a550862a823ece1eee987d0c334ac.png

然后我们在来测试

721c7a84ec54c48a01517f4213c8b3e1.png

间隔一分钟去访问user那个路由,我们的token就已经刷新了

851e10d6bd61a1c2d06b7021bc26e313.png

这边需要注意一点就是token刷新之后就会进入黑名单,之后就不能在进行刷新

所以项目在特殊情况下需要设置这几个参数

b5d1f987b4239e26ddd08431dde022b8.png

1732594a74b0a34a4a70cfeaf722df3f.png

这里需要注意一个问题,中间件谁在前就会执行谁

404a93adcc9efdaa18f22e36d6eca9a7.png

90acc2be5ce29c8e5896ddadd4aaf20a.png

在文章一开始就说了需要判断用户是否登录,由于jwt里边不存在check的检验方法,所以我们自己定义一个webCheck方法

因为在项目中曾经修改过配置文件,把api的认证改为了jwt的认证守卫,

4d18765e71628a55c255f9c0df132fb2.png

这个守卫就位于\vendor\tymon\src

032bd910b1452521479a2995374581e6.png

在之前使用auth(‘api’)-> attempt 的时候实际就是执行的下面的方法。

4997930d06ed86b5d81f90521dc98480.png

直接进入login的方法

1d86ddf6e1dcec0df0963c5b739fdfcc.png

实际上登入的方法参数中并没有太多的操作,就是校验用户的信息,然后再设计登入之后的user

也就是在这个过程中会直接返回出user用户的信息;

而在正常情况下使用auth的时候是可以,因为是使用的web,也就是auth.php中的配置

264ecdbd332fff369d7cf02398073ee4.png

也就是使用的是SessionGurad , 直接进入login方法

ad12a3edcd9aec07455ffb35ca6e480d.png

在通过getAuthIdentifier()方法完成,完成之后然后再设置session缓存;

也就是说用户的信息会缓存在session中

那么来看一下校验;

JWTGurad与SessionGuard的校验,通过查找源码会发现并不存在check方法,这个方法位于Illuminate\Auth\GuardHelpers中;

2b409a5bbcd8b6649841ef3dbd27a351.png

可以看到实际就是使用对应guard(web,api)中的user方法,也就是通过user方法获取用户,如果说用户不存在就会返回false;

bac77dc9c7852adeff12f3b1341e829b.png

827c7f29d0cbbdff21f7147289564272.png

简单解释:

jwt的校验过程:最为重要的点就在于,通过request获取jwt然后再去解析获取用的信息;

session的校验就是从session中获取用户的id然后再去数据库中查询用户

所以这就是问题所以在;那么针对于这个问题的话,既希望能够保持jwt对于api认证,又希望在web端校验(会员登入)

最好的解决办法就是在JWTGurad中添加一个webCheck的校验方法;但是实际上这样也不并不是很好因为版本会更新所以最好的办法就是扩展自定义guard

在项目中通过Auth:: guard (‘守卫名称’) 就可以解析出所需要的守卫;

d35a9ca15239c82e37f70508ec619311.png

然后再通过resolve方法去解析出这个守卫;

1391d32740cb92ed73a0d118376877a6.png

发现这个类中有一个数组customCreators,这说明,我们是可以自定义driver的。也就是说,虽然config/auth.php的guards中说driver只支持session和token,但实际上是可以自己扩展的。

可以测试一下

在这个地方通过dd打印扩展的Guard

8299606e1ccd496c9c82bc0ffecb098e.png

为了方便测试,接下来所有的测试路由均放置于routes/test.php中,并且以test为前缀;并且中间件为web 组

abb4e0b429bb1f0a92e6062737cb41d7.png

然后访问

805420b392960731055ca550d380c8a7.png

那怎么扩展呢,顺藤摸瓜,发现class AuthManager中有一个方法extend:

1cf7d59aecd1da2ec760e4d83b309e33.png

然后看一下是怎么加载JWTGuard的

打开jwt的

db66080b020e15d0c291d3b32806e481.png

这个extendAuthGuard就是在父级AbstractServiceProvider中的方法

d71f32d3181c320ffe0de038dde8f32f.png

可以从方法中就可以看到这就是加载JWTGuard的方法所在;也就是对于auth的guard扩展

其实也就是说JWTGuard 的扩展载入是通过与服务提供LaravelServiceProvider中的boot载入的

接下来自定义一个auth的guard,并且继承与JWTGuard

21f973e5515121aad2b7ff4b13a074ce.png

然后建议这个时候就对于这个Guard进行扩展加入做测试;模仿JWTGuard的载入方式而操作的,

914cfed88b33ade915a74a5683ef56b3.png

然后修改config/auth.php

74f3dc85246e9834f1e857072141daa2.png

在访问

4e09746d119caa37c7c06ea178e11404.png

下来完善自定义的app\Auth\JWTSessionGuard.php的代码

1.       重写JWTGuard控制器

2.       然后加入session的载入 注意RedisFactory 是use Illuminate\Contracts\Session\Session;

3.       下一步在登入成功之后调用updateSession 缓存用户的id

<?phpnamespace App\Auth;use Tymon\JWTAuth\JWT;use Tymon\JWTAuth\JWTGuard;use Illuminate\Http\Request;use Illuminate\Contracts\Session\Session;use Illuminate\Contracts\Auth\UserProvider;use Tymon\JWTAuth\Contracts\JWTSubject;class JWTSessionGuard extends JWTGuard{protected $session;public function __construct(JWT $jwt, UserProvider $provider, Request $request , Session $session){$this->session = $session ;parent::__construct($jwt, $provider, $request);}public function login(JWTSubject $user){$token = $this->jwt->fromUser($user);$this->setToken($token)->setUser($user);$this->updateSession($user->id);return $token;}protected function updateSession($id){$this->session->put($this->getName(), $id);$this->session->migrate(true);}public function getName(){return 'login_jwt_' . sha1(static::class);}}

最后修改AuthServiceProvider中的boot方法

914cfed88b33ade915a74a5683ef56b3.png

然后在测试

ccfdb7b5d4331f8288cb082e498e95cd.png

4c48995b6af3810ba7e085f13bfcda8e.png

然后在测试一下,直接验证成功

6049ae602b7db6b41743d75abd3d0446.png

a122c6a25414d966e4e7d936d9ca9982.png

添加中间件

dba61af5d0fe479becaff1a09462b386.png

af75fbb215a5dd659398ccfa45d55d3d.png

然后还需要引入俩个中间件

6494d3af308c07613b109b6f22a105aa.png

然后在回到咱们用户登录的控制器

aa3729d48abc0557a025f046501f30f8.png

修改路由

0071ae3e96c44a8f74dd26d3ac79fded.png

然后测试,目前就把token本地存储,还有token的刷新就全部弄完了

4df06404d2933a17581f9a98c42df870.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/508094.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

php orm 链式,关于php:雄辩的ORM中的交叉和分页

大家好&#xff0c;我有3张桌子&#xff1a;具有以下属性的名为content的表&#xff1a;idnametable_type_idrelease_datepopularity另一个名为content_genres的表&#xff0c;具有以下属性&#xff1a;content_idgenres_id另一个具有以下属性的表&#xff0c;称为genres&#…

2019java形势,2019Java开发还有哪些发展

相信已经有不少人在心里考虑着春节之后转行新工作了吧&#xff0c;而在众多行业中IT行业&#xff0c;特别是Java开发、Java程序员等岗位相信是很多人的首选。谁让现在程序员薪资这么高呢&#xff0c;但是现在互联网发展迅速&#xff0c;各类编程语言层出不穷&#xff0c;比如py…

php取消转译代码,PHP在我不需要的时候进行转义

我有一个问题,即PHP在我不希望它出现在代码中的地方进行转义:$url_ stripslashes(((substr(strtolower($url),0,7)!"http://")? "http://".$url:$url));$host $this->googleDomains[mt_rand(0,count($this->googleDomains)-1)];$target "/s…

matlab给plc发送命令,想学习下如何将PLC发送的指令让软件接收到?

PLC作为下位机&#xff0c;接收上位机的执行命令&#xff0c;并将执行结果反馈给上位机。工具/原料电脑、PLC、USB转RS232数据线和RS232转RS485模块(或者USB转RS485)方法/步骤PLC与电脑线路连接&#xff0c;根据电脑的串口情况&#xff0c;1.电脑自带RS232串口&#xff0c;那么…

mysql允许两个用户远程连接,配置MySQL服务允许用户远程连接

默认情况下&#xff0c;mysql只允许本地登录&#xff0c;如果要开启远程连接&#xff0c;则需要修改/etc/mysql/my.conf文件。一、修改/etc/mysql/my.conf找到bind-address 127.0.0.1这一行改为bind-address 0.0.0.0即可二、为需要远程登录的用户赋予权限1、新建用户远程连接…

pupload 文件分块 php,基于Plupload实现Base64分割的文件上传方案

标题&#xff1a;基于Plupload实现Base64分割的文件上传方案关键词&#xff1a;文件上传、Base64、Plupload、Blob、分割上传领域&#xff1a;Web前端作者&#xff1a;孙振强日期&#xff1a;2018-04-13目录背景存在问题2.1. 体积增加1/32.2. 大文件上传不稳定方案思路3.1. 将服…

php imagick手册,PHP中使用Imagick实现各种图片效果实例

这篇文章主要介绍了PHP中使用Imagick实现各种图片效果实例,本文讲解了偏置图像、改变图片大imagick是一个功能强大的图像处理库。说是翻译 其实就是简要介绍imagick 的主要功能的或者说是我觉得比较实用的功能函数的介绍 以及使用的例子。因为本人的英语水平有限&#xff0c;所…

php流程控制的类型有哪些,流程控制包括哪些内容

流程控制也称为控制流程&#xff0c;是计算机运算领域的用语&#xff0c;其内容包括在程序运行时&#xff0c;个别的指令或是陈述、子程序运行或求值的顺序&#xff0c;不论是在声明式编程语言或是函数编程语言中&#xff0c;都有类似的概念。控制流程(也称为流程控制)是计算机…

PHP公鸡五文钱,公鸡

中国古代数学家张丘建在他的《算经》中提出了一个著名的“百钱买百鸡问题”&#xff0c;鸡翁一&#xff0c;值钱五&#xff0c;鸡母一&#xff0c;值钱三&#xff0c;鸡雏三&#xff0c;值钱一&#xff0c;百钱买百鸡&#xff0c;问翁、母、雏各几何&#xff1f;实现过程&#…

oracle11g创建闪回分区多大,Oracle闪回区大小预估

一个朋友问如何设置Oracle闪回区大小&#xff0c;有什么依据没有。查证官方文档&#xff0c;有如下描述For example, if you intend to setDB_FLASHBACK_RETENTION_TARGET to 24 hours, and if the database generates 20 GB of redo in a day, then a rule of thumb is to all…

平方变换法提取载波MATLAB,毕业设计(论文)MPSK信号的载波同步算法研究与仿真.doc...

目录摘要IAbstractII第一章 绪论1相移键控技术1第二章 载波同步原理22.1平方变换法和平方环法22.2 同相正交3第三章 相移键控(PSK)信号的调制原理63.1 二进制相移键控的基本原理63.2 二进制差分相移键控(DPSK)的基本原理83.3 多进制相移键控(MPSK)的基本原理113.3.1 QPSK调制原…

oracle dba_waiters中的lockid是什么,查杀oracle lock session and table

查杀oracle 死锁的一些帖子摘录[more]查找死锁进程column sid format 999;column b format 9;column object_name format a30;select v$lock.sid,decode(v$lock.type,MR, Media Recovery,RT,Redo Thread,UN,User Name,TX, Transaction,TM, DML,UL, PL/SQL User Lock,DX, Distri…

查询linux服务器事物传输失败日志,查看fail2ban日志代替lastb查看登录失败记录

之前我曾经用shell脚本提取lastb登录失败超过指定次数的IP加入到iptables&#xff0c;来禁止这些IP登录主机&#xff0c;达到防止恶意攻击的目的。后来为了给主机提供更全面的防护&#xff0c;又安装了fail2ban。今天早上我收到fail2ban发过来的报警邮件提示我禁止了一个IP登录…

文件字符串变量插入linux,Linux Shell脚本实现在文件指定的行插入字符串

涉及知识点&#xff1a;grep字符串查找&#xff0c;awk截取列&#xff0c;until条件操作&#xff0c;sed字符串插入&#xff0c;变量与字符串连接等。人工操作(首先vim打开文件找到字符串所在的位置&#xff0c;插入操作)&#xff1a;vim /etc/glance/glance-api-paste.ini# Li…

linux系统子接口配置文件,Linux网卡绑定、子接口-IP别名

查看网卡线缆状态&#xff1a;mii-tool eth0查看网卡底层信息&#xff1a;ethtool eth0ethtool -i eth0 查看网卡驱动信息ethtool -S eth0 查看网卡状态统计信息Linux下可以通过IP别名(子接口)功能为一个物理网卡添加多个IP地址要使用IP别名(子接口)需要关闭NetworkManager服…

linux防火墙允许dns服务,Linux防火墙设置-DNS服务器篇

亲测可用&#xff0c;对于刚刚搭建了DNS服务器&#xff0c;需要开启防火墙但又不知道该怎么设置的朋友&#xff0c;可以参考下面的内容&#xff0c;或者直接使用我下面给出的脚本程序。如果服务器是作为DNS服务器使用的&#xff0c;针对绝大多数的情况&#xff0c;为了开启防火…

发布react项目到linux服务器,nginx上部署react项目的实例方法

测试项目&#xff1a;react-demo克隆你的react-demo项目到服务器上(默认使用Github管理我们的项目)如果需要&#xff0c;请安装项目环境&#xff0c;比如&#xff1a;node.js&#xff0c;yarn等进入项目目录&#xff0c;执行npm run build&#xff0c;开始构建项目构建成功之后…

linux取消线程的原理,浅析 Linux 进程与线程

简介进程与线程是所有的程序员都熟知的概念&#xff0c;简单来说进程是一个执行中的程序&#xff0c;而线程是进程中的一条执行路径。进程是操作系统中基本的抽象概念&#xff0c;本文介绍 Linux 中进程和线程的用法以及原理&#xff0c;包括创建、消亡等。进程创建与执行Linux…

linux查看注册表信息,linux下登录档及其查看方法

一、Linux 常见的登录档档名登录档可以帮助我们瞭解很多系统重要的事件&#xff0c;包括登入者的部分资讯&#xff0c;因此登录档的权限通常是设定为仅有 root 能够读取而已。 而由于登录档可以记载系统这麽多的详细资讯&#xff0c;所以啦&#xff0c;一个有经验的主机管理员会…