侯体宗的博客 JWT源码实现逻辑详解

石可破,丹可磨
  • 首页
  • laravel8仿版
  • beego仿版
  • go_聊天
  • 人生
  • 技术
  • php
  • 架构
  • 数据库
  • 更多
    • 文件下载
    • 匿名群聊
    • 群聊(进来吹会!)
    • 留言
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册
    • 设置栏目
    • 更多设置
    • 分割线

JWT源码实现逻辑详解

Laravel  /  管理员 发布于 2021-02-03 15:33:36   83

描述:

Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于 JSON 的开放标准((RFC 7519). 该 token 被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT 的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该 token 也可直接被用于认证,也可被加密。


详细信息可查看什么是 JWT – JSON WEB TOKEN(https://www.jianshu.com/p/576dbf44b2ae),这里就不做过多介绍。

在项目中我使用了 tymon/jwt-auth 扩展包,所以根据对这个包进行源码分析,了解其具体的实现逻辑

通过集成这个包,我们可以在 config.auth.php 中修改看守器的驱动,将 driver 修改为 jwt

'guards' => [
        'api' => [
            'driver' => 'jwt',
            'provider' => 'users',
        ],
    ],

在用户登录,可通过 Auth::guard('api')->attempt(['email'=>$'email,'password'=>$password]); 校验用户登录并返回 token


其中校验密码的过程,我们一般将用户的密码通过 bcrypt () 函数进行加密,通过 bcrypt () 函数即使密码相同,生成的字符串也不相同。然后通过 password_verify () 函数验证密码是否和散列值匹配。


用户登录校验完成后,会返回如下的字符串,这个字符串就是 token, 它分为三个部分,第一部分我们称它为头部(header), 第二部分我们称其为载荷(payload, 类似于飞机上承载的物品),第三部分是签证(signature),通过. 将字符串连接在一起。

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9lbGVtZW50LXNob3AudGVzdFwvYWRtaW5cL2FwaVwvbG9naW4iLCJpYXQiOjE2MTE4OTAwNDUsImV4cCI6MTYxMjEwNjA0NSwibmJmIjoxNjExODkwMDQ1LCJqdGkiOiJMTnQ3N01yaXlNUDVKRmFaIiwic3ViIjoyLCJwcnYiOiJhMjNiNTczZGM3M2E0MDdlOGRlNTNiNDg2ZjM2ODg2YWRmNzBjNDgzIn0.B4bHALzb5lg0z-G2iU3wwiYb4r18-wUa0TVH_V1X1IE


通过查看源码实现,其中 encode () 用于生成 token,decode () 用于解析 token

/**
     * Create a JSON Web Token.
     *
     * @param  array  $payload
     *
     * @throws \Tymon\JWTAuth\Exceptions\JWTException
     *
     * @return string
     */
    public function encode(array $payload)
    {
        // Remove the signature on the builder instance first.
        $this->builder->unsign();
        try {
            foreach ($payload as $key => $value) {
                $this->builder->set($key, $value);
            }
            $this->builder->sign($this->signer, $this->getSigningKey());
        } catch (Exception $e) {
            throw new JWTException('Could not create token: '.$e->getMessage(), $e->getCode(), $e);
        }
        return (string) $this->builder->getToken();
    }

继续查看生成 token 逻辑

/**
     * Returns the resultant token
     *
     * @return Token
     */
    public function getToken(Signer $signer = null, Key $key = null)
    {
        //为声明的加密算法,这里为HS256,可在./config/jwt.php中配置algo参数修改
        $signer = $signer ?: $this->signer;
        //token加密私钥,只存储在服务端,也是实现token最重要的一环,可在./config/jwt.php中配置secret参数修改
        //一般通过php artisan jwt:secret命令生成
        $key = $key ?: $this->key;
        if ($signer instanceof Signer) {
            //在token头部添加加密算法
            $signer->modifyHeader($this->headers);
        }
        //生成token的第一部分和第二部分
        $payload = [
            //将["typ" => "JWT","alg" => "HS256"]数组转为字符串并进行base64加密形成token的header
            $this->encoder->base64UrlEncode($this->encoder->jsonEncode($this->headers)),
            //其中的$this->claims为token的载荷数组转为字符串并进行base64加密形成token的payload,内容包括
            //iss: jwt签发者
            //sub: jwt所面向的用户 
            //exp: jwt的过期时间,这个过期时间必须要大于签发时间
            //nbf: 定义在什么时间之前,该jwt都是不可用的.
            //iat: jwt的签发时间
            //jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
            $this->encoder->base64UrlEncode($this->encoder->jsonEncode($this->claims))
        ];
        //生成签名,使用hash_hmac($this->getAlgorithm(), $payload, $key->getContent(), true)生成签名,其中$this->getAlgorithm()为加密算法HS256,$payload为token的第一,二部分,$key为加密私钥
        $signature = $this->createSignature($payload, $signer, $key);
        if ($signature !== null) {
            //将签名进行base64加密返回
            $payload[] = $this->encoder->base64UrlEncode($signature);
        }
        return new Token($this->headers, $this->claims, $signature, $payload);
    }

查看解析 token 的代码

/**
     * Decode a JSON Web Token.
     *
     * @param  string  $token
     *
     * @throws \Tymon\JWTAuth\Exceptions\JWTException
     *
     * @return array
     */
    public function decode($token)
    {
        try {
            //解析token,将token分割为三部分头部,负载,签名。对数据进行base64解码并json_decode转为数组,若解析失败抛出异常
            $jwt = $this->parser->parse($token);
        } catch (Exception $e) {
            throw new TokenInvalidException('Could not decode token: '.$e->getMessage(), $e->getCode(), $e);
        }
        //使用hash_equals内置函数对token解析的签名与hash_hmac($this->getAlgorithm(), $payload, $key->getContent(), true)比较是否相同,若相同则表示认证通过,不同则直接抛出异常
        if (! $jwt->verify($this->signer, $this->getVerificationKey())) {
            throw new TokenInvalidException('Token Signature could not be verified.');
        }
        //认证通过返回payload的内容
        return (new Collection($jwt->getClaims()))->map(function ($claim) {
            return is_object($claim) ? $claim->getValue() : $claim;
        })->toArray();
    }


总结:

1.以上就是生成和解析 token 的大致逻辑,其中加密的关键还是在于服务器生成的私钥,若私钥流失,客户端就可以自己根据逻辑生成 token。

2.payload 要防止存放敏感信息,因为该部分是客户端可解密的部分。

3.想自己造轮子也知道逻辑。

4.面试的时候问到也不虚了。


转:https://learnku.com/articles/54009


昵称:

邮箱:

0条评论
最新最热
  • 分类目录
  • 人生 (119)
  • 技术 (46)
  • linux (23)
  • blog从零开始 (9)
  • php (48)
  • 架构 (14)
  • 前端 (22)
  • TP(3/5) (14)
  • 数据库 (29)
  • 微信 (2)
  • Laravel (56)
  • Redis (3)
  • Docker (2)
  • Go (8)
  • 近期文章
  • PHP程序员2021年最新面试题集-持续更新中...(0个评论)
  • PHP数组的底层实现原理浅析(0个评论)
  • php7垃圾回收变量的GC机制详解(0个评论)
  • 在Laravel中进行类型转换详解(0个评论)
  • mysql数据库中事务的四个特征及四种隔离级别的浅析描述(0个评论)
  • Linux awk 命令及统计nginx日志里访问次数最多的前十个IP(0个评论)
  • 论不要在mysql中使用[utf8]编码,如果要用请用[utf8mb4](0个评论)
  • JWT源码实现逻辑详解(0个评论)
  • Laravel内核分析-设计模式之观察者模式(0个评论)
  • Laravel内核分析-设计模式之装饰模式(0个评论)
  • 近期评论
  • 请教 在

    国内用什么翻墙使用谷歌?上外网神器Ghelper插件详解中评论 你好,我也遇到了安装完右上角没有显示图标,也不能打开相关网页的问题,用的是谷歌浏..
  • Test11 在

    laravel查询构造器中whereNotKey,whereKey,firstWhere用法详解中评论 <script>alert(\test\)</script&g..
  • 博主 在

    国内用什么翻墙使用谷歌?上外网神器Ghelper插件详解中评论 @西瓜: 每一步都操作完达到效果了吗? 对了是用谷歌浏览器吧..
  • 西瓜 在

    国内用什么翻墙使用谷歌?上外网神器Ghelper插件详解中评论 你好 我安装完右上角没有显示图标,也不能打开相关网页,是怎么回事呢?..
  • 博主 在

    laravel-admin 添加Excel导入功能中评论 这应该算是比较详细了吧, 你是哪一步没看懂吗?..
  • 文章归档
  • 2016-10 (34)
  • 2016-11 (21)
  • 2017-06 (5)
  • 2017-07 (11)
  • 2017-08 (6)
  • 2017-09 (7)
  • 2017-10 (11)
  • 2017-11 (4)
  • 2017-12 (3)
  • 2018-01 (9)
  • 2018-02 (2)
  • 2018-03 (2)
  • 2018-04 (1)
  • 2018-05 (3)
  • 2018-06 (1)
  • 2018-10 (1)
  • 2018-11 (1)
  • 2020-03 (5)
  • 2020-04 (85)
  • 2020-05 (42)
  • 2020-06 (35)
  • 2020-07 (22)
  • 2020-08 (11)
  • 2020-09 (14)
  • 2020-10 (7)
  • 2020-11 (8)
  • 2020-12 (6)
  • 2021-01 (6)
  • 2021-02 (6)
  • 2021-03 (2)
Top
  • 友情链接
  • 侯体宗的博客
  • 三防加固笔记本
  • 澜溪博客
  • 心中hope
  • 徒步认知的博客
  • 陈大剩博客
  • 赵波的博客
  • 佘春晓的博客
  • 自动友链系统

Auther ·HouTiZong© 2009-2020 zongscan.com 版权所有ICP证: 粤ICP备20027696号 PHP交流群 也可以扫右边的二维码

侯体宗的博客