PHPJWT的使用

今天得空整理整理JWT的代码

  1. 首先,我们得知道什么是JWT?

JWT(JSON Web Token)是一种开放标准(RFC7519),用于在网络应用环境中安全地传输声明信息。它是一种紧凑的、URL安全的令牌格式,常用于身份验证和信息交换。

当然,他也是支持解密的,地址:https://jwt.io/

2、它能用来干什么?

随着技术的发展,分布式web应用的普及,通过session管理用户登录状态成本越来越高,因此慢慢发展成为token的方式做登录身份校验,然后通过token去取redis中的缓存的用户信息,随着之后jwt的出现,校验方式更加简单便捷化,无需通过redis缓存,而是直接根据token取出保存的用户信息,以及对token可用性校验,单点登录更为简单。

3、什么时候你应该用JSON Web Tokens

1、Authorization (授权) :这是使用JWT的最常见场景。一旦用户登录,后续每个请求都将包含JWT,允许用户访问该令牌允许的路由、服务和资源。单点登录是现在广泛使用的JWT的一个特性,因为它的开销很小,并且可以轻松地跨域使用。

2、Information Exchange (信息交换) : 对于安全的在各方之间传输信息而言,JSON Web

Tokens无疑是一种很好的方式。因为JWTs可以被签名,例如,用公钥/私钥对,你可以确定发送人就是它们所说的那个人。另外,由于签名是使用头和有效负载计算的,您还可以验证内容没有被篡改。

4、JSON Web Token的结构是什么样的

5、JSON Web Token由三部分组成,它们之间用圆点(.)连接。这三部分分别是:

  1. Header
  2. Payload
  3. Signature

6、因此,一个典型的JWT看起来是这个样子的:

xxxxx.yyyyy.zzzzz

7、组成部分

header

典型的由两部分组成:token的类型("JWT")和算法名称(比如:HMAC SHA256或者RSA等等)。

然后,用Base64对这个JSON编码就得到JWT的第一部分
Payload

JWT的第二部分是payload,它包含声明(要求)。声明是关于实体(通常是用户)和其他数据的声明。声明有三种类型: registered,public 和 private。

Registered claims : 这里有一组预定义的声明,它们不是强制的,但是推荐。比如:iss (issuer), exp(expiration time), sub (subject), aud (audience)等。

Public claims : 可以随意定义。

Private claims : 用于在同意使用它们的各方之间共享信息,并且不是注册的或公开的声明。 下面是一个例子:

对payload进行Base64编码就得到JWT的第二部分

注意,不要在JWT的payload或header中放置敏感信息,除非它们是加密的。

Signature

为了得到签名部分,你必须有编码过的header、编码过的payload、一个秘钥,签名算法是header中指定的那个,然对它们签名即可。

bash 复制代码
例如:HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

签名是用于验证消息在传递过程中有没有被更改,并且,对于使用私钥签名的token,它还可以验证JWT的发送方是否为它所称的发送方。

8、大家请看,生成一个JWTtoken,然后神奇的一幕来了,将这串token放进上方jwt官网地址地址中,即将解密,如下图所示:


9、那么?JSON Web Tokens是如何工作的???

1、应用(或者客户端)想授权服务器请求授权。例如,如果用授权码流程的话,就是/oauth/authorize

2、当授权被许可以后,授权服务器返回一个access token给应用

3、应用使用access token访问受保护的资源(比如:API)

10、所以说,上方的操作方式是非常不安全的。所以我们即将采用,对称加密,每个用户加解密都使用一个共同的密钥key

11. 安装jwt扩展

composer require firebase/php-jwt

12. 安装加解密扩展,当然,不想使用此方法也可使用其他方法加解密。

composer require defuse/php-encryption

13. 废话不多说,直接上代码

php 复制代码
	/**
     *  生成 JWT
     * @param $data
     * @return false|string
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function makeJwtSecretKey($data)
    {
        // 这里的key是加密的key,需永久保存使用,建议保存到数据库的配置中或者env文件中
        $key = self::getJwtConfig(); 

        $payload = [
            'iat' => time(), // 签发时间
            'exp' => time() + Constant::JWT_EXP, // 过期时间
            'jti' => Utils::getValue($data, 'id'), // 添加一个唯一标识符
            'data' => [
                'pxo' => Utils::getValue($data, 'id'),
                'nickname' => Utils::getValue($data, 'nickname'),
                'area_code' => Utils::getValue($data, 'area_code'),
            ]
        ];

        // 编码 jwt,这里采用 HS256 加密
        $encode = JWT::encode($payload, $key, 'HS256');
        // 创建随机key,这个key是要保存起来的,对用户进行加解密
        $createKey = \Defuse\Crypto\Key::createNewRandomKey();
        $createKeyAscii = $createKey->saveToAsciiSafeString();
        $token =  Crypto::encrypt($encode, $createKey);
        $encry_key = base64_encode($createKeyAscii);

        $user_id = Utils::getValue($data, 'id');
        // 之所以这里使用redis保存encry_key是因为,这个key是非常重要的,不能暴露给外界看到,所以我在生成jwt的时候直接就将这个使用redis缓存起来,方便解析使用。
        RedisUtils::set('user_encry_key_' . $user_id, $encry_key, Constant::JWT_EXP);
        $res = User::where('id', $user_id)->update(['token' => $token, 'encry_key' => $encry_key]);
        if (!Utils::isValid($res)){
            return false;
        }

        return $token;
    }
php 复制代码
	/**
     *  解码JWT
     * @param $token
     * @return int|\stdClass
     */
    public static function deJwtSecretKey($token, $userModel)
    {
        try {
            $key = self::getJwtConfig();

            $user_id = Utils::getValue($userModel, 'id');
            $encry_key = RedisUtils::get('user_encry_key_' . $user_id);
            $decryptionKey = \Defuse\Crypto\Key::loadFromAsciiSafeString(base64_decode($encry_key));
            $decodedToken = Crypto::decrypt($token, $decryptionKey);

            return JWT::decode($decodedToken, new Key($key, 'HS256'));
        } catch (ExpiredException $e) {
            //  这里处理令牌过期,这里的异常写的1,2我好容易区分是哪里出的问题。
            return 1;
        } catch (\Exception $e) {
            // 处理其他可能的异常
            Log::info( "Failed to decode token: " . $e->getMessage());
            return 2;
        }
    }
php 复制代码
$deUserModel = JwtService::deJwtSecretKey($token, $userModel);
if (!is_object($deUserModel)){
	 switch ($deUserModel) {
	     case 1 :
	         $token = JwtService::makeJwtSecretKey($userModel);
	         if (!Utils::isValid($token)){
	             return Utils::fail(lang('用户唯一凭证生成失败'));
	         }
	         break;
	     case 2 :
	         $this->error(lang('令牌验证失败'));
	         break;
	 }
}

以上,大致也就这样了,其实还是蛮简单的奥,也希望大家能多多学习与交流

相关推荐
两个人的幸福13 天前
Windows 桌面应用自研 PHP 队列(下):完整代码与六大工程化优化
php
BingoGo15 天前
PHP 泛型之殇 泛型 RFC 提案被拒绝
后端·php
JaguarJack15 天前
PHP 泛型之殇 泛型 RFC 提案被拒绝
后端·php
用户30745969820716 天前
PHP 扩展——从入门到理解
php
鹏仔先生17 天前
拷贝漫画APP下载页PHP程序,后台带免费AI写作
php
云水一下17 天前
从零开始学 PHP 系列(一):PHP 的前世今生与开发环境搭建
开发语言·php
xingpanvip17 天前
星盘接口开发文档:本命盘接口指南
android·开发语言·css·php·lua
酉鬼女又兒17 天前
零基础入门计算机网络运输层:端到端通信核心作用、端口号分类规则、复用分用工作机制及UDP与TCP协议全方位对比详解
网络·网络协议·tcp/ip·计算机网络·考研·udp·php
dog25017 天前
不要再继续优化 TCP
网络协议·tcp/ip·php
Channing Lewis17 天前
PHP 解析 Excel 的那些坑:一次“行号错位”引发的数据丢失
开发语言·php·excel