当前位置: 首页 > 后端技术 > PHP

在API开发中,可以选择传递token接口遇到坑

时间:2023-03-29 15:37:39 PHP

在做API开发的时候,难免会涉及到登录验证。我使用jwt-auth,登录时经常遇到token过期问题。在config/jwt.php的默认设置中,过期时间是一小时,但为了安全可以设置得更小。我把它设置为五分钟。它在五分钟后到期。如果你让用户登录,这种体验会让用户直接放弃你的网站,所以这个会用到刷新token的功能。一般会写一个刷新token的接口。过期时,前端会带上过期的token,请求该接口换取新的token。不过为了前端方便,也可以使用后端刷新返回,直到无法刷新为止。这是我使用的方法:使用Jwt-Auth实现API用户认证,无痛刷新accesstoken而坑就是这样来的,设置refreshtokencheckForToken($request);try{/********************************************尝试通过tokne登录,如果正常的话会得到用户*无法正确登录,抛出token异常********************************************/if($this->auth->parseToken()->authenticate()){返回$next($request);}thrownewUnauthorizedHttpException('jwt-auth','Usernotfound');}catch(TokenExpiredException$e){try{/*******************************************token过期异常,尝试刷新token*使用id进行一次性登录,保证本次请求成功******************************************/$token=$this->auth->refresh();$id=$this->auth->manager()->getPayloadFactory()->buildClaimsCollection()->toPlainArray()['sub'];auth()->onceUsingId($id);}catch(JWTException$e){/*****************************************如果捕获到这个异常,说明刷新已经过期,*用户无法刷新token,需要重新登录*******************************************/thrownewUnauthorizedHttpException('jwt-auth',$e->getMessage(),null,StatusServe::HTTP_PAYMENT_REQUIRED);}}//在响应头中返回一个新的令牌return$this->setAuthenticationHeader($next($request),$token);}}还有一些页面,比如文章列表页面,这个界面可以登录也可以不访问,但是登录后可以在页面显示是否喜欢这篇文章。所以这个接口直接使用jwt-auth的默认option中间件**有关完整的版权和许可信息,请查看与此源代码一起分发的LICENSE*文件。*/namespaceTymon\JWTAuth\Http\Middleware;useClosure;useException;classCheckextendsBaseMiddleware{/***处理传入请求。**@param\Illuminate\Http\Request$request*@param\Closure$next**@returnmixed*/publicfunctionhandle($request,Closure$next){if($this->auth->parser()->setRequest($request)->hasToken()){尝试{$this->auth->parseToken()->authenticate();}catch(Exception$e){}}返回$next($request);}}一开始没发现问题。直到测试,我在文章列表页面找到了我喜欢的文章。过了一段时间,刷新的时候发现点赞没有显示,但是进入个人中心后可以看到点过赞的文章。刚开始测试的时候,并没有找出原因。我直接暴力破解代码,发现没有获取到登录用户。还以为不对,为什么传过来的token拿不到。发现后,进入个人中心,再回到新闻列表页面,可以正常显示,过一会就显示不出来了。这一轮下来,大概明白了新闻列表页面的token已经过期了,但是当时方便使用的jwt-auth默认的中间件不会刷新token,所以这个接口获取不到logged-在用户中。进入个人中心,发现当前token已经过期,后台刷新token返回。此时返回文章列表页面即可获取正常数据。一段时间后,token又失效了,就看不到被点赞的文章了。解决办法是自己写一个option中间件。当token存在时,也需要刷新token。auth->parser()->setRequest($request)->hasToken()){尝试{$this->auth->parseToken()->authenticate();}catch(TokenExpiredException$e){//这里做刷新token处理//具体代码可以参考mustberequired登录认证接口//在响应头中返回一个新的tokenreturn$this->setAuthenticationHeader($next($请求),$令牌);}catch(Exception$e){}}返回$next($request);}}问题解决了。最后说一个并发问题:#当前token_1过期了,先发起一个请求,然后立即向服务器发起一个b请求#一个请求到服务器,服务器判断已经过期,刷新token_1#然后返回token_2给arequestresponse#这个稍晚了b请求还是用token_1#服务器已经把这个token_1加入了黑名单,所以b请求无效token_1刷新返回token_2arequest-------->server------->successfultoken_1expiredtoken_1,shouldUsetoken_2brequest-------->server------>failurejwt-auth已经想到了这种情况,我们只需要设置一个黑名单grace时间,我设置为5秒,即当token_1过期后,可以继续使用token_15秒操作原地址