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,一经查实,立即删除!

相关文章

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

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

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、新建用户远程连接…

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

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

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…

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

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

linux双屏播放视频,Ubuntu Linux下双屏显示解决方案

Ubuntu从起后居然把Windows的设置给记住了。显示ok。我晕。以前倒是也有过这问题&#xff0c;在双系统情况下&#xff0c;外接键盘的灯会继承Windows的早就有心弄个显示器&#xff0c;把笔记本的外接上&#xff0c;倒不是说非要2个屏幕来工作如何如何&#xff1f;只是因为我的本…

鸟哥linux群,【鸟哥的linux私房菜-学习笔记】linux的帐号与群组

linux的帐号与群组使用者标识符&#xff1a; UID 与 GIDID 与账号的对应就在 /etc/passwd 当中&#xff1b;计算机只认得ID(即数字)&#xff0c;并不能区别账号&#xff1b;每个登陆的使用者至少都会取得两个 ID &#xff0c;一个是使用者 ID (User ID &#xff0c;简称 UID)、…

C语言中表示温度符号,摄氏度符号怎么打(SCI论文中摄氏度°C符号的正确输法)...

大家可能知道中文的摄氏度百思特网是一个字符&#xff0c;而且输入方法比较简单&#xff0c;可以用搜狗输入法&#xff0c;还可以输入 "sheshidu"&#xff0c;第五个一般就是℃&#xff0c;甚至可以在网上或文献中复制粘贴。而英文的摄氏度C 却是两个字符&#xff0c…

android filehelper,为AndroidStudio开发mvp插件(MvpHelper)

如果觉得写mvp有点枯燥无味&#xff0c;我们可以做点 cool 的事情&#xff1a;做个 as 插件help.pngtodo-mvp: 基础的MVP架构。todo-mvp-loaders:基于MVP架构的实现&#xff0c;在获取数据的部分采用了loaders架构。todo-mvp-databinding: 基于MVP架构的实现&#xff0c;采用了…

android+5.q,MSM8909+Android5.1.1电池管理(2)--qpnp-linear-charger.txt驱动学习概要

MSM8909Android5.1.1电池管理(2)--qpnp-linear-charger.txt驱动学习概要参考文件\kernel\Documentation\power\qpnp-linear-charger.txt---下面是学习此文件\kernel\Documentation\devicetree\bindings\power\qpnp-linear-charger.txt1. 简介The QPNP linear charger drive…

岳阳鸿蒙数学培优阶梯训练,鸿蒙应用-呼吸训练app部分练习展示(开始)

本帖最后由 李洋水蛟龙 于 2020-12-20 18:11 编辑1.在主页面添加一个按钮并响应点击事件效果显示&#xff1a;图片1.png (404.17 KB, 下载次数: 0)2020-12-10 17:53 上传点击按钮“点我”下方便会显示“我被点击了”说明点击事件已完成代码如下&#xff1a;Index.hml文件中Hell…

android日期选择滚轮框架,GitHub - liwenzhi/wheelview: 滚轮效果的View,日期选择器

#wheelview滚动效果的View这段时间需要用到一个时间选择器&#xff0c;但是不能使用日期对话框&#xff0c;因为它是筛选条件框架下的&#xff0c;只能是View&#xff01;这个WheelView改造后可以达到要求&#xff01;这个wheelview框架使用的类不多&#xff0c;就几个&#xf…

大学计算机基础知识点图文,大学计算机基础知识点超详细总结

大学计算机基础知识点超详细总结 第一章 计算机及信息技术概述1. 电子计算机的发展历程①1946 年 2 月由宾夕法尼亚大学研制成功的 ENIAC 是世界上第一台电子数字计算机。 “诞生了一个电子的大脑” 致命缺陷&#xff1a;没有存储程序。②电子技术的发展促进了电子计算机的更新…

js复制html到粘贴板,用clipboard.js实现纯JS复制文本到剪切板

以前很多人都是用ZeroClipboard.js来实现网页复制内容&#xff0c;火端也是用它。ZeroClipboard是利用flash来实现的&#xff0c;ZeroClipboard兼容性很好&#xff0c;但是由于现在越来越多的浏览器不支持flash&#xff0c;导致一些没法正常使用了。今天火端开始使用clipboard.…

计算机设备的存放,计算机硬件储存设备与网络储存的发展现状

计算机的出现&#xff0c;改变了人们的生活和生产&#xff0c;而计算机硬件技术的发展&#xff0c;则为计算机储存开辟了新的发展方向和途径。而随着时代的进步&#xff0c;计算机储存技术的发展也是日新月异&#xff0c;现在我们所使用的云储存技术&#xff0c;就是储存技术发…

计算机键盘没有fn,键盘Fn键失灵怎么解决?键盘Fn键失灵的修复方法

电脑键盘是电脑输入设备中最常用的设备之一&#xff0c;也是大家使用最频繁的的设备。其实键盘Fn键占据着很大分量,Fn键能够实现很多功能,如控制音量、打开关闭摄像头、屏幕亮度调节等。如果Fn键失灵的话,那就会对电脑造成很大的影响&#xff0c;有什么办法修复&#xff1f;下面…

网站的服务器分哪几种,服务器有哪几种分类?_服务器可分为四种类型

办事器能够按使用分&#xff1a;OA办事器、数据库办事器、流媒体办事器、高机能计较办事器、逛戏办事器等。软盘接口是软盘取从机系统间的毗连部件&#xff0c;感化是正在软盘缓存和从机内存之间传输数据。分歧的软盘接口决定灭软盘取计较机之间的毗连速度&#xff0c;正在零个…

英雄联盟服务器维护3月17,英雄联盟将于3月17日凌晨2点开始进行全区停机维护...

原标题&#xff1a;英雄联盟全区停机维护公告英雄联盟将于3月17日凌晨2点开始进行全区停机维护&#xff0c;公告如下&#xff1a;我们将于3月17日2点开始全区停机维护以进行后台服务升级&#xff0c;预计在凌晨1点关闭排位赛入口&#xff0c;不会影响正在进行中的排位赛。预计停…

网站服务器时间秒杀,Javascript实现商品秒杀倒计时(时间与服务器时间同步)...

现在有很多网站都在做秒杀商品&#xff0c;而这其中有一个很重要的环节就是倒计时。关于倒计时&#xff0c;有下面几点需要注意&#xff1a;1.应该使用服务器时间而不是本地时间(本地时间存在时区不同、用户自行设置等问题)。2.要考虑网络传输的耗时。3.获取时间时可直接从AJAX…

i7 8700 服务器系统,i7 8700k 云服务器

i7 8700k 云服务器 内容精选换一换您可以在几分钟之内快速获得基于公有云平台的弹性云服务器设施&#xff0c;并且这些设施是弹性的&#xff0c;可以根据需求伸缩。该任务指导用户如何创建支持IB网卡的弹性云服务器&#xff0c;包括管理控制台方式和基于HTTPS请求的API(Applica…