个人github博客: https://zgxxx.github.io/
上一篇博客文章https://segmentfault.com/a/11... 介绍了laravel使用dingo+jwt开发API的几个步骤,那么在实际操做中,咱们须要测试APIphp
$api = app('Dingo\Api\Routing\Router'); $api->version('v1', ['namespace' => 'App\Http\Controllers\V1'], function ($api) { $api->post('register', 'AuthController@register'); $api->post('login', 'AuthController@login'); $api->post('logout', 'AuthController@logout'); $api->post('refresh', 'AuthController@refresh'); $api->post('me', 'AuthController@me'); $api->get('test', 'AuthController@test'); });
设置了这几个路由,对应的url相似这样:http://www.yourweb.com/api/me 使用postman来调试这些API。前端
咱们使用jwt代替session,首先是经过登陆(jwt的attempt方法验证帐号密码),成功后会返回一个JWT,咱们把这个字符串统一叫作token,这个token须要咱们客户端保存起来,而后后面须要认证的接口就在请求头里带上这个token,后台验证正确后就会进行下一操做,若是token错误,或者过时就返回401或500错误,拒绝后面的操做。laravel
前端能够保存在localStorage,小程序能够 使用wx.setStorageSync保存
因此请求头信息Authorization:Bearer + token很重要,可是有个问题,这个token是有一个刷新时间和过时时间的:'ttl' => env('JWT_TTL', 60),
'refresh_ttl' => env('JWT_REFRESH_TTL', 20160),
git
token是会被别人盗取的,因此token须要每隔一段时间就更新一次
这时候有个问题,每隔一小时就更新,那岂不是要每小时就从新登陆一遍来获取新token?固然不须要,咱们能够写个中间件来实现无痛刷新token,用户不会察觉咱们已经更新了token。github
<?php namespace App\Http\Middleware; 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 RefreshToken extends BaseMiddleware { /** * @author: zhaogx * @param $request * @param Closure $next * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Response|mixed * @throws JWTException */ 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(); // 使用一次性登陆以保证这次请求的成功 \Auth::guard('api')->onceUsingId($this->auth->manager()->getPayloadFactory()->buildClaimsCollection()->toPlainArray()['sub']); } catch (JWTException $exception) { // 若是捕获到此异常,即表明 refresh 也过时了,用户没法刷新令牌,须要从新登陆。 throw new UnauthorizedHttpException('jwt-auth', $exception->getMessage()); } } return $next($request)->withHeaders([ 'Authorization'=> 'Bearer '.$token, ]); } }
一旦中间件检测到token过期了,就自动刷新token,而后在响应头把新的token返回来,咱们客户端能够根据响应头是否有'Authorization'来决定是否要替换token
在使用postman调试这些API的时候就有个问题,postman又没有前端代码,我怎么及时更新这个token,难道每次请求都要去看响应头,发现Authorization后手动去复制黏贴吗,固然也不须要,postman有个强大的环境变量,其实也是前端js的东西。web
首先点击设置环境这个按钮,点击Add按钮添加一个变量,咱们设置key值为access_token,json
接着咱们在登陆接口的Tests中去赋值这个变量小程序
var data = JSON.parse(responseBody); if (data.result.access_token) { tests["Body has token"] = true; var tokenArray = data.result.access_token.split(" "); postman.setEnvironmentVariable("access_token", tokenArray[1]); } else { tests["Body has token"] = false; }
这段js代码就是获取请求成功后返回的access_token值,将其赋值给postman的环境变量,咱们看到请求成功后咱们后台返回了一个json,其中就有咱们须要的access_token,咱们能够再去环境变量那里看看这时候的变量有什么变化segmentfault
能够看到这里的变量access_token已经有值了,就是咱们后台返回来的access_token字符串,说明赋值成功api
接着咱们到另外一个须要认证的接口测试
咱们在Authorization类型type选择Bearer Token,在后面Token表单那里打一个'{'就会自动提示咱们设置过的变量{{access_token}}
发送请求测试下
已经成功了。
那若是token刷新了,通过后台中间件无痛刷新后,会在响应头返回一个新的token(这一次请求用的是旧的token,默认认证经过)
如今咱们须要在这个接口上直接更新咱们的变量access_token(以下图),而不须要去再请求一遍登陆接口
var authHeader = postman.getResponseHeader('Authorization'); if (authHeader){ var tokenArray = authHeader.split(" "); postman.setEnvironmentVariable("access_token", tokenArray[1]); tests["Body has refreshtoken"] = true; } else { tests["Body has no refreshtoken"] = false; }
这段js代码就是将响应头中的Authorization赋值给咱们的access_token
这是响应头的Authorization,截取了最后面的字符串
刷新时间过了后,咱们试着再发一次请求,咱们能够看到,仍是能够访问的,并且请求头里的Authorization已经自动更新过来了
用一句话整理大概就是,你须要在哪一个接口响应后更新变量,就去这个这个口的Test下写js赋值代码postman.setEnvironmentVariable("access_token", token);
,只要没错误你就能够在别的地方使用{{access_token}}更新替换了。