关键词搜索

源码搜索 ×
×

ThinkPHP6 使用JWT 实现用户认证以及无痛刷新访问令牌

发布2021-09-08浏览2914次

详情内容

使用的是thans/tp-jwt-auth 包。支持Header、Cookie、Param等多种传参方式。包含验证并且自动刷新等多种中间件。

官网:https://gitee.com/thans/jwt-auth

环境要求

  1. php >= 7.0
  2. thinkphp ^5.1.10 || ^6.0.0

我这里使用的是ThinkPHP6 + PHP7.3

安装

composer require thans/tp-jwt-auth

执行以下命令,将生成jwt.php,并且.env中会随机生成secret,请不要随意更新secret,也请保障secret安全。

php think jwt:create

使用方式:对于需要验证的路由或者模块添加中间件:

 thans\jwt\middleware\JWTAuth::class

自定义认证中间件

说明:调用登录接口,成功则返回token给前端,所有需要用户认证的路由都需要在头部携带此token。(格式:将token加入header,如下:Authorization:bearer token值)
同时,后端会判断用户token是否过期,如果过期了会刷新token,并且在响应header返回新的token给前端,前端需要判断响应header有没token,如果有,则直接使用此 token 替换掉本地的 token,以此达到无痛刷新token效果。

创建用户认证中间件:

php think make:middleware JWT

代码:

  1. <?php
  2. declare (strict_types=1);
  3. namespace app\api\middleware;
  4. use thans\jwt\exception\JWTException;
  5. use thans\jwt\exception\TokenBlacklistException;
  6. use thans\jwt\exception\TokenBlacklistGracePeriodException;
  7. use thans\jwt\exception\TokenExpiredException;
  8. use thans\jwt\middleware\JWTAuth;
  9. use think\exception\HttpException;
  10. /**
  11. * JWT验证刷新token机制
  12. * Class JWTToken
  13. * @package app\api\middleware
  14. */
  15. class JWT extends JWTAuth
  16. {
  17. /**
  18. * 刷新token
  19. * @param $request
  20. * @param \Closure $next
  21. * @return mixed
  22. * @throws JWTException
  23. * @throws TokenBlacklistException
  24. * @throws TokenBlacklistGracePeriodException
  25. */
  26. public function handle($request, \Closure $next): object
  27. {
  28. try {
  29. $payload = $this->auth->auth();
  30. } catch (TokenExpiredException $e) { // 捕获token过期
  31. // 尝试刷新token,会将旧token加入黑名单
  32. try {
  33. $this->auth->setRefresh();
  34. $token = $this->auth->refresh();
  35. $payload = $this->auth->auth(false);
  36. } catch (TokenBlacklistGracePeriodException $e) {
  37. $payload = $this->auth->auth(false);
  38. } catch (JWTException $exception) {
  39. // 如果捕获到此异常,即代表 refresh 也过期了,用户无法刷新令牌,需要重新登录。
  40. throw new HttpException(401, $exception->getMessage());
  41. }
  42. } catch (TokenBlacklistGracePeriodException $e) { // 捕获黑名单宽限期
  43. $payload = $this->auth->auth(false);
  44. } catch (TokenBlacklistException $e) { // 捕获黑名单,退出登录或者已经自动刷新,当前token就会被拉黑
  45. throw new HttpException(401, '未登录..');
  46. }
  47. // 可以获取payload里自定义的字段,比如uid
  48. $request->uid = $payload['uid']->getValue();
  49. $response = $next($request);
  50. // 如果有新的token,则在响应头返回(前端判断一下响应中是否有 token,如果有就直接使用此 token 替换掉本地的 token,以此达到无痛刷新token效果)
  51. if (isset($token)) {
  52. $this->setAuthentication($response, $token);
  53. }
  54. return $response;
  55. }
  56. }

在路由中使用中间件

  1. Route::group(function () {
  2. Route::get('user', 'user/index');
  3. })->middleware(\app\api\middleware\JWT::class);

登录接口

  1. ......
  2. // 登录逻辑省略
  3. $user = xxxx;
  4. // 生成token,参数为用户认证的信息,请自行添加
  5. $token = JWTAuth::builder(['uid' => $user->id]);
  6. return [
  7. 'token' => 'Bearer ' . $token
  8. ];
  9. ......

使用Postman进行测试,注意参数名是:Authorization

前端自定义响应拦截器

  1. axios.interceptors.response.use((response) => {
  2. // 判断响应中是否有token,如果有则使用此token替换掉本地的token
  3. this.refreshToken(response);
  4. return response
  5. }, (error) => {
  6. // 判断错误响应中是否有token,如果有则使用此token替换掉本地的token
  7. this.refreshToken(error.response);
  8. switch (error.response.status) {
  9. // http状态码为401,则清除本地的数据并跳转到登录页面
  10. case 401:
  11. localStorage.removeItem('token');
  12. console.log('需要重新登录')
  13. break;
  14. // http状态码为400,则弹出错误信息
  15. case 400:
  16. console.log(error.response.data.error);
  17. break;
  18. }
  19. return Promise.reject(error)
  20. })
  21. .......
  22. methods: {
  23. // 刷新token
  24. refreshToken(response) {
  25. let token = response.headers.authorization
  26. if (token) {
  27. localStorage.setItem('token', token);
  28. }
  29. }
  30. }

前端需要用户认证请求示例

  1. axios.get('xxx', {
  2. headers: {
  3. Authorization: localStorage.getItem('token')
  4. }
  5. }).then(response => {
  6. console.log(response)
  7. }).catch(error => { //请求失败,error接收失败原因
  8. console.log(error);
  9. });


作者:皮蛋馅儿
链接:https://www.jianshu.com/p/b1e7606c6168
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

相关技术文章

点击QQ咨询
开通会员
返回顶部
×
微信扫码支付
微信扫码支付
确定支付下载
请使用微信描二维码支付
×

提示信息

×

选择支付方式

  • 微信支付
  • 支付宝付款
确定支付下载