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;
	 }
}

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

相关推荐
BingoGo1 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php
JaguarJack1 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php·服务端
BingoGo2 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php
JaguarJack2 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php·服务端
JaguarJack3 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
后端·php·服务端
BingoGo3 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
php
JaguarJack4 天前
告别 Laravel 缓慢的 Blade!Livewire Blaze 来了,为你的 Laravel 性能提速
后端·php·laravel
郑州光合科技余经理5 天前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php
QQ5110082855 天前
python+springboot+django/flask的校园资料分享系统
spring boot·python·django·flask·node.js·php
WeiXin_DZbishe5 天前
基于django在线音乐数据采集的设计与实现-计算机毕设 附源码 22647
javascript·spring boot·mysql·django·node.js·php·html5