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 相关文章推荐
多重?l件?合查?(一)
Oct 09 PHP
PHP通用分页类page.php[仿google分页]
Aug 31 PHP
php快速url重写 更新版[需php 5.30以上]
Apr 20 PHP
PHP数组无限分级数据的层级化处理代码
Dec 29 PHP
jquery获取多个checkbox的值异步提交给php的方法
Jun 24 PHP
PHP实现加密文本文件并限制特定页面的存取的效果
Oct 21 PHP
Yii2中添加全局函数的方法分析
May 04 PHP
PHP与Perl之间知识点区别整理
Mar 19 PHP
Yii2框架操作数据库的方法分析【以mysql为例】
May 27 PHP
laravel-admin自动生成模块,及相关基础配置方法
Oct 08 PHP
Laravel 实现添加多语言提示信息
Oct 25 PHP
PHP页面静态化――纯静态与伪静态用法详解
Jun 05 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
PHP防止sql注入小技巧之sql预处理原理与实现方法分析
Dec 13 #PHP
You might like
FleaPHP的安全设置方法
2008/09/15 PHP
php 404错误页面实现代码
2009/06/22 PHP
关于Appserv无法打开localhost问题的解决方法
2009/10/16 PHP
PHP人民币金额数字转中文大写的函数代码
2013/02/27 PHP
php+mysql删除指定编号员工信息的方法
2015/01/14 PHP
php把时间戳转换成多少时间之前函数的实例
2016/11/16 PHP
详解php协程知识点
2018/09/21 PHP
php中的explode()函数实例介绍
2019/01/18 PHP
js判断变量是否未定义的代码
2020/03/28 Javascript
js实现简洁大方的二级下拉菜单效果代码
2015/09/01 Javascript
AngularJS ng-app 指令实例详解
2016/07/30 Javascript
jquery中用函数来设置css样式
2016/12/22 Javascript
Bootstrap组合上、下拉框简单实现代码
2017/03/06 Javascript
浅谈vue的几种绑定变量的值 防止其改变的方法
2018/03/01 Javascript
vue2.0 + element UI 中 el-table 数据导出Excel的方法
2018/03/02 Javascript
微信小程序实现展示评分结果功能
2019/02/15 Javascript
element-ui组件中input等的change事件中传递自定义参数
2019/05/22 Javascript
layer.prompt使文本框为空的情况下也能点击确定的方法
2019/09/24 Javascript
微信小程序上传帖子的实例代码(含有文字图片的微信验证)
2020/07/11 Javascript
Python二维码生成库qrcode安装和使用示例
2014/12/16 Python
Python的mysql数据库的更新如何实现
2017/07/31 Python
python先序遍历二叉树问题
2017/11/10 Python
Python实现按照指定要求逆序输出一个数字的方法
2018/04/19 Python
Python实现快速计算词频功能示例
2018/06/25 Python
Python 移动光标位置的方法
2019/01/20 Python
Python类的继承、多态及获取对象信息操作详解
2019/02/28 Python
set在python里的含义和用法
2019/06/24 Python
python文件读写代码实例
2019/10/21 Python
原来我一直安装 Python 库的姿势都不对呀
2019/11/11 Python
在spyder IPython console中,运行代码加入参数的实例
2020/04/20 Python
HTML5 Canvas实现图片缩放、翻转、颜色渐变的代码示例
2016/02/28 HTML / CSS
美国购买舞会礼服网站:Couture Candy
2019/12/29 全球购物
大学生活自我评价
2014/04/09 职场文书
幼儿园师德师风学习材料
2014/05/29 职场文书
2015年度工程师评职称工作总结
2015/10/14 职场文书
2016年度员工工作表现评语
2015/12/02 职场文书