Laravel jwt 多表验证隔离

发布时间 - 2019-07-03 00:00:00    点击率:

为什么要做隔离

当同一个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,
    "prv": "92d5e8eb1b38ccd11476896c19b0e44512b2aacd"
}

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

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

解决办法

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

添加自定义信息到token

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

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,
    "prv": "92d5e8eb1b38ccd11476896c19b0e44512b2aacd",
    "role": "admin"
}

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

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

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

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

编写jwt角色校验中间件

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

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多表用户验证隔离。

更多Laravel相关技术文章,请访问Laravel教程栏目进行学习!


# laravel  # 自定义  # 的是  # 主键  # 会像  # 自己的  # 就会  # 文档  # 会有  # 就能  # 多个 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: Edge浏览器提示“由你的组织管理”怎么解决_去除浏览器托管提示【修复】  如何挑选最适合建站的高性能VPS主机?  高防服务器租用如何选择配置与防御等级?  Laravel怎么清理缓存_Laravel optimize clear命令详解  郑州企业网站制作公司,郑州招聘网站有哪些?  Python进程池调度策略_任务分发说明【指导】  如何在 Pandas 中基于一列条件计算另一列的分组均值  Laravel与Inertia.js怎么结合_使用Laravel和Inertia构建现代单页应用  Bootstrap整体框架之CSS12栅格系统  Laravel项目怎么部署到Linux_Laravel Nginx配置详解  合肥制作网站的公司有哪些,合肥聚美网络科技有限公司介绍?  laravel怎么为应用开启和关闭维护模式_laravel应用维护模式开启与关闭方法  Laravel怎么写单元测试_PHPUnit在Laravel项目中的基础测试入门  如何在宝塔面板中修改默认建站目录?  如何在服务器上配置二级域名建站?  google浏览器怎么清理缓存_谷歌浏览器清除缓存加速详细步骤  如何快速选择适合个人网站的云服务器配置?  Laravel怎么进行数据库回滚_Laravel Migration数据库版本控制与回滚操作  Laravel如何实现模型的全局作用域?(Global Scope示例)  ai格式如何转html_将AI设计稿转换为HTML页面流程【页面】  如何用PHP快速搭建CMS系统?  韩国代理服务器如何选?解析IP设置技巧与跨境访问优化指南  如何用西部建站助手快速创建专业网站?  Android Socket接口实现即时通讯实例代码  如何用腾讯建站主机快速创建免费网站?  如何在 Python 中将列表项按字母顺序编号(a.、b.、c. …)  WEB开发之注册页面验证码倒计时代码的实现  如何构建满足综合性能需求的优质建站方案?  香港服务器租用每月最低只需15元?  LinuxShell函数封装方法_脚本复用设计思路【教程】  Laravel如何升级到最新版本?(升级指南和步骤)  如何在建站之星网店版论坛获取技术支持?  Laravel如何使用缓存系统提升性能_Laravel缓存驱动和应用优化方案  Laravel如何从数据库删除数据_Laravel destroy和delete方法区别  Laravel Artisan命令怎么自定义_创建自己的Laravel命令行工具完全指南  Laravel如何保护应用免受CSRF攻击?(原理和示例)  nginx修改上传文件大小限制的方法  Laravel如何生成URL和重定向?(路由助手函数)  Laravel如何配置Horizon来管理队列?(安装和使用)  焦点电影公司作品,电影焦点结局是什么?  关于BootStrap modal 在IOS9中不能弹出的解决方法(IOS 9 bootstrap modal ios 9 noticework)  Python面向对象测试方法_mock解析【教程】  jquery插件bootstrapValidator表单验证详解  在线制作视频网站免费,都有哪些好的动漫网站?  微信小程序 input输入框控件详解及实例(多种示例)  JS弹性运动实现方法分析  javascript读取文本节点方法小结  如何用ChatGPT准备面试 模拟面试问答与职场话术练习教程  Linux后台任务运行方法_nohup与&使用技巧【技巧】  javascript中对象的定义、使用以及对象和原型链操作小结