Laravel jwt 多表(多用户端)验证隔离的实现


Posted in PHP onDecember 18, 2019

Tips: tymon/jwt-auth 作者已通过增加 prv 字段修复这一问题#1167,但是如果你是用 dingo api + jwt 的话,该问题依然存在。#

JWT 多表验证隔离

为什么要做隔离

当同一个 laravel 项目有多端(移动端、管理端......)都需要使用 jwt 做用户验证时,如果用户表有多个(一般都会有),就需要做 token 隔离,不然会发生移动端的 token 也能请求管理端的问题,造成用户越权。

会引发这个问题的原因是 laravel 的 jwt token 默认只会存储数据表的主键的值,并没有区分是那个表的。所以只要 token 里携带的 ID 在你的用户表中都存在,就会导致越权验证。

我们来看看 laravel 的 jwt token 的原貌:

{
 "iss": "http://your-request-url",
 "iat": 1558668215,
 "exp": 1645068215,
 "nbf": 1558668215,
 "jti": "XakIDuG7K0jeWGDi",
 "sub": 1
}

携带数据的是 sub 字段,其他字段是 jwt 的验证字段。

我们只看到 sub 的值为 1,并没有说明是那个表或是哪个验证器的。这个 token 通过你的验证中间件时,你使用不同的 guard 就能拿到对应表 id 为 1 的用户(了解 guard 请查看 laravel 的文档)。

解决办法

想要解决用户越权的问题,我们只要在 token 上带上我们的自定义字段,用来区分是哪个表或哪个验证器生成的,然后再编写自己的中间件验证我们的自定义字段是否符合我们的预期。

添加自定义信息到 token

我们知道要使用 jwt 验证,用户模型必须要实现 JWTSubject 的接口(代码取自jwt 文档):

<?php

namespace App;

use Tymon\JWTAuth\Contracts\JWTSubject;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable implements JWTSubject
{
 use Notifiable;

 // Rest omitted for brevity

 /**
  * Get the identifier that will be stored in the subject claim of the JWT.
  *
  * @return mixed
  */
 public function getJWTIdentifier()
 {
  return $this->getKey();
 }

 /**
  * Return a key value array, containing any custom claims to be added to the JWT.
  *
  * @return array
  */
 public function getJWTCustomClaims()
 {
  return [];
 }
}

我们可以看看实现的这两个方法的作用:

  • getJWTIdentifier 的:获取会储存到 jwt 声明中的标识,其实就是要我们返回标识用户表的主键字段名称,这里是返回的是主键 'id',
  • getJWTCustomClaims:返回包含要添加到 jwt 声明中的自定义键值对数组,这里返回空数组,没有添加任何自定义信息。

接下来我们就可以在实现了 getJWTCustomClaims 方法的用户模型中添加我们的自定义信息了。

管理员模型:

/**
 * 额外在 JWT 载荷中增加的自定义内容
 *
 * @return array
 */
public function getJWTCustomClaims()
{
 return ['role' => 'admin'];
}

移动端用户模型:

/**
 * 额外在 JWT 载荷中增加的自定义内容
 *
 * @return array
 */
public function getJWTCustomClaims()
{
 return ['role' => 'user'];
}

这里添加了一个角色名作为用户标识。

这样管理员生成的 token 会像这样:

{
 "iss": "http://your-request-url",
 "iat": 1558668215,
 "exp": 1645068215,
 "nbf": 1558668215,
 "jti": "XakIDuG7K0jeWGDi",
 "sub": 1,
 "role": "admin"
}

移动端用户生成的 token 会像这样:

{
 "iss": "http://your-request-url",
 "iat": 1558668215,
 "exp": 1645068215,
 "nbf": 1558668215,
 "jti": "XakIDuG7K0jeWGDi",
 "sub": 1,
 "role": "user"
}

我们可以看到这里多了一个我们自己加的 role 字段,并且对应我们的用户模型。

接下来我们自己写一个中间件,解析 token 后判断是否是我们想要的角色,对应就通过,不对应就报 401 就好了。

编写 jwt 角色校验中间件

这里提供一个可全局使用的中间件 (推荐用在用户验证中间件前):

<?php
/**
 * Created by PhpStorm.
 * User: wlalala
 * Date: 2019-04-17
 * Time: 13:55
 */

namespace App\Http\Middleware;

use Closure;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
use Tymon\JWTAuth\Exceptions\JWTException;
use Tymon\JWTAuth\Http\Middleware\BaseMiddleware;

class JWTRoleAuth extends BaseMiddleware
{
 /**
  * Handle an incoming request.
  *
  * @param $request
  * @param Closure $next
  * @param null $role
  * @return mixed
  */
 public function handle($request, Closure $next, $role = null)
 {
  try {
   // 解析token角色
   $token_role = $this->auth->parseToken()->getClaim('role');
  } catch (JWTException $e) {
   /**
    * token解析失败,说明请求中没有可用的token。
    * 为了可以全局使用(不需要token的请求也可通过),这里让请求继续。
    * 因为这个中间件的责职只是校验token里的角色。
    */
   return $next($request);
  }

  // 判断token角色。
  if ($token_role != $role) {
   throw new UnauthorizedHttpException('jwt-auth', 'User role error');
  }

  return $next($request);
 }
}

注册 jwt 角色校验中间件

在 app/Http/Kernel.php 中注册中间件:

/**
  * The application's route middleware.
  *
  * These middleware may be assigned to groups or used individually.
  *
  * @var array
  */
 protected $routeMiddleware = [
  // ...省略 ...

  // 多表jwt验证校验
  'jwt.role' => \App\Http\Middleware\JWTRoleAuth::class,
 ];

使用 jwt 角色校验中间件

接下来在需要用户验证的路由组中添加我们的中间件:

Route::group([
 'middleware' => ['jwt.role:admin', 'jwt.auth'],
], function ($router) {
 // 管理员验证路由
 // ...
});

Route::group([
 'middleware' => ['jwt.role:user', 'jwt.auth'],
], function ($router) {
 // 移动端用户验证路由
 // ...
});

至此完成 jwt 多表用户验证隔离。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
为IP查询添加GOOGLE地图功能的代码
Aug 08 PHP
php array_unique之后json_encode需要注意
Jan 02 PHP
Zend Studio (eclipse)使用速度优化方法
Mar 23 PHP
MySQL连接数超过限制的解决方法
Jul 17 PHP
分享下PHP register_globals 值为on与off的理解
Sep 26 PHP
php中字符查找函数strpos、strrchr与strpbrk用法
Nov 18 PHP
PHP+MySQL修改记录的方法
Jan 21 PHP
php生成不重复随机数、数组的4种方法分享
Mar 30 PHP
php示例详解Constructor Prototype Pattern 原型模式
Oct 15 PHP
用php和jQuery来实现“顶”和“踩”的投票功能
Oct 13 PHP
php实现微信企业付款到个人零钱功能
Oct 09 PHP
ThinkPHP类似AOP思想的参数验证的实现方法
Dec 18 PHP
PHP中用Trait封装单例模式的实现
Dec 18 #PHP
PHP实现微信公众号验证Token的示例代码
Dec 16 #PHP
浅析PHP中的 inet_pton 网络函数
Dec 16 #PHP
Laravel等框架模型关联的可用性浅析
Dec 15 #PHP
php获取是星期几的的一些常用姿势
Dec 15 #PHP
Yii2框架中一些折磨人的坑
Dec 15 #PHP
关于Yii2框架跑脚本时内存泄漏问题的分析与解决
Dec 01 #PHP
You might like
mac下Apache + MySql + PHP搭建网站开发环境
2014/06/02 PHP
简单实现php上传文件功能
2017/09/21 PHP
详解PHP中的外观模式facade pattern
2018/02/05 PHP
thinkPHP5框架auth权限控制类与用法示例
2018/06/12 PHP
JQUERY复选框CHECKBOX全选,取消全选
2008/08/30 Javascript
javascript window对象属性整理
2009/10/24 Javascript
Jquery 滑入滑出效果实现代码
2010/03/27 Javascript
JavaScript 面向对象之命名空间
2010/05/04 Javascript
jquery中对表单的基本操作代码
2010/07/29 Javascript
asp.net中oracle 存储过程(图文)
2015/08/12 Javascript
bootstrap table插件的分页与checkbox使用详解
2017/07/23 Javascript
Vue 实现双向绑定的四种方法
2018/03/16 Javascript
浅谈微信小程序flex布局基础
2018/09/10 Javascript
基于js Canvas实现二次贝塞尔曲线
2018/12/25 Javascript
jquery绑定事件 bind和on的用法与区别分析
2020/05/22 jQuery
JQuery获得内容和属性方法解析
2020/05/30 jQuery
处理JavaScript值为undefined的7个小技巧
2020/07/28 Javascript
原生JavaScript实现贪吃蛇游戏
2020/11/04 Javascript
[49:05]OG vs Newbee 2019DOTA2国际邀请赛淘汰赛 胜者组 BO3 第二场 8.21.mp4
2020/07/19 DOTA
python基础教程之字典操作详解
2014/03/25 Python
python使用os.listdir和os.walk获得文件的路径的方法
2017/12/16 Python
Python 实现取多维数组第n维的前几位
2019/11/26 Python
给Python学习者的文件读写指南(含基础与进阶)
2020/01/29 Python
python实现Oracle查询分组的方法示例
2020/04/30 Python
pandas apply使用多列计算生成新的列实现示例
2021/02/24 Python
详解CSS3 用border写 空心三角箭头 (两种写法)
2017/09/29 HTML / CSS
世界领先的豪华床上用品供应商之一:Bedeck Home
2019/03/18 全球购物
澳大利亚家具商店:Freedom
2020/12/17 全球购物
仓管员岗位职责范文
2013/11/08 职场文书
财务部绩效考核方案
2014/05/04 职场文书
银行求职自荐信
2014/06/30 职场文书
综合测评个人总结
2015/03/03 职场文书
2015年乡镇安全生产工作总结
2015/05/19 职场文书
教师培训简讯
2015/07/20 职场文书
2019年最新七夕唯美祝福语(60条)
2019/07/22 职场文书
SpringBoot2零基础到精通之数据库专项精讲
2022/03/22 Java/Android