ThinkPHP8中使用JWT生成Token和验证Token

发布时间:2023-08-23浏览次数:1510 次
网上有很多关于jwt生成token和验证token的文章,以及在thinkphp中使用jwt的文章,但是感觉都比较散乱,因此计划自己从头梳理总结一番。一、JWT

网上有很多关于jwt生成token和验证token的文章,以及在thinkphp中使用jwt的文章,但是感觉都比较散乱,因此计划自己从头梳理总结一番。

一、JWT简介

所谓JWT,是Json Web Token的简称,是Auth2.0验证授权方式中的一种常见方式,也是目前非常流行的跨域认证解决方案。当然官方一点的解释是:JWT是一种轻量级的认证和授权机制,使用JSON对象作为安全令牌,可以在多个系统之间安全的传输用户身份信息

在学习JWT之前,我们先回顾以下几年前我们常用的后端登录认证方式。客户端将用户名和密码等信息发送给服务端,服务端通过认证后在session和cookie中存储认证信息(具体点说就是将认证信息存储在session中,然后将对应的session_id存储在cookie中,以后每次请求时都会自动从cookie中读取并携带这个session_id,进而再从服务端的session中取出认证信息)。这种方式在多年之前基本是通行标准。因为那个时候,网站的前端基本和后端都是在一个域名下的。

然而,随着各种终端的出现,如app、小程序、微信公众号等,此时,传统的认证授权方式就不能满足新的需求了(当然,我们也可以把之前session中存储的数据放到redis中来完成)。此时,我们就需要一种,可以在不同终端(即跨域)之间解决认证授权的方案。当然,要强调的是,JWT是很早就有的方案,只是我们以前在PHP相关应用中用的不多,并不是有了多个终端之后才出现的。

二、JWT的结构

JWT生成的Token是一个很长的字符串,中间用点(·)分隔成三个部分,如下:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vYXBpLnRvcGNtcy5pbyIsImlhdCI6MTY5Mjc1NDkyOSwiZXhwIjoxNjkyODQxMzI5LCJkYXRhIjp7ImlkIjoxLCJ1c2VybmFtZSI6InFpZXR1amlhbmciLCJyb2xlIjoxfX0.3uRgHU6nC3Of-xiFmtxJdf_wsP3_HfOymhHD0NM_biE

被点(·)号分隔成的三部分,分别为:Header(头部)、Payload(载荷)、Signature(签名)。即:

Header.Payload.Signature

其中,Header和Payload两个部分串型化的算法是Base64URL。这个算法跟Base64算法基本相似,但不同之处在于,Base64URL算法会替换掉Base64编码结果里面的+/=,替换规则为:=被省略,+替换为-/替换为_。在PHP中,我们可以使用base64_encode()和base64_decode()函数来进行Base64编码和解码,但是没有现成的Base64URL函数,因此,我们需要自行对Base64编码的结果再次进行加工。如:

$str = 'http://www.qietujiang.com';
$base64 = base64_encode($str);
$base64url = trim(strtr($base64,'+/=','-_ '));
echo $base64."<HR />";
echo $base64url.$str."<HR />";

当然这块的实现方式很多,也可以使用,str_replace函数,具体的大家可根据自己的编码习惯去完成。

其实,目前我们生成JWT基本都是使用第三方很成熟的库,但是在很久之前,我们都是自己动手去写代码,然后生成JWT的。这里,我们为了更好的梳理,先自行完成JWT的生成,然后我们再使用第三方库来帮我们完成。

2.1 Header 头部

jwt的header部分是一个JSON对象,描述JWT的元数据,通常如下:

{
	"alg": "HS256",
	"typ": "JWT"
}

上面代码中:alg属性为algorithm的缩写,表示签名的算法,默认为HMAC SHA256(写成HS256

typ属性为type的缩写,表示令牌token的类型,JWT令牌统一写为JWT

使用PHP手动生成header的方法如下:

$header = [
    'alg'=>'HS256',
    'typ'=>'JWT'
];
echo trim(strtr(base64_encode(json_encode($header)),'+/=','-_'));
// 结果为:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

 

2.2 Payload 载荷

Payload部分用来存放实际需要传递的数据,也是一个JSON对象,JWT规定了7个官方字段(实际使用中,也不是都必须填写),除此之外,我们还可以在这个不分定义一些私有字段,但是要注意,JWT默认是不加密的,任何人都可以读到,所以不要把重要信息放在这个部分。

1、iss(issuer )签发者:issuer请求实体,可以是发起请求的用户的信息,也可以是jwt的签发者
2、sub(subject )主题:类似于发送邮件时设置的主题
3、aud(audience )受众(接收者):接收jwt的一方,接收人
4、exp(expire )过期时间:值为时间戳,token的过期时间,一般都是设置为 time() + token有效时长
5、nbf(not before)生效时间:值为时间戳,即在此时间值钱,token不可使用(无效)
6、iat(issuedat) 签发时间:token的创建时间,一般为 time()
7、jti  (JWT ID) 编号: 对当前token设置唯一标识

Payload部分也是使用Base64URL算法转为字符串,如下:

$payload = [
    'iss' => 'http://api.topcms.io',
    'exp' => time() + 3600,
    'iat' => time(),
    'data' => [
        'id' => 1,
        'username' => '切图匠',
        'role' => 1
    ]
];

echo trim(strtr(base64_encode(json_encode($payload)),'+/=','-_'));

//输出:eyJpc3MiOiJodHRwOlwvXC9hcGkudG9wY21zLmlvIiwiZXhwIjoxNjkyODQxMzI5LCJpYXQiOjE2OTI3NTQ5MjksImRhdGEiOnsiaWQiOjEsInVzZXJuYW1lIjoiXHU1MjA3XHU1NmZlXHU1MzIwIiwicm9sZSI6MX19

2.3 Signature 签名

签名部分是对前面的Header和Payload两个部分的签名,用来防止数据被篡改。在生成Signature时,需要指定一个密钥 Secret,这个密钥只有服务端知道,不可泄露给用户。

生成Signature签名的方式:使用在header中约定的签名算法(默认为 HMAC SHA256),按下面的公式生成签名。

$secret = 'cbc6c831cfe3e21448070ba99b******'; // 密钥

$data = base64_encode(trim(strtr(json_encode($header),'+/=','-_ '))) . '.' .
base64_encode(trim(strtr(json_encode($payload),'+/=','-_ ')));
$signature = hash_hmac('sha256', $data, $secret);
echo $signature;
// 输出:6122637bc4818f04dc0d756c19e656b8bb0726ed953cd338746dc3c9c72b0bfd

在php中,我们使用hash_hmac()函数来计算HMAC-SHA256哈希值。

最后,再将我们分别生成的 Header、Payload和Signature三个部分链接起来,中间使用点(·)进行分隔,组成的字符串即为最终的token。也是最终返回给用户的令牌。

三、JWT的使用方式

客户端收到服务端返回的JWT之后,可以存储在本地,一般使用Cookie或localStore。伺候,客户端每次与服务端通信时,都需要带上这个JWT。如果是同一个域名,可以把它放在cookie里,自动发送。但是如果是不同终端,即存在跨域问题时,最好的做法是将其放在HTTP的请求头信息Authorization字段里面。如,在axios的请求拦截器里:

const token = localStorage.getItem('token');
if (token) {
    config.headers.Authorization = "Bearer "+token;

    return config;
}
return config;

四、JWT的几个特点

1、jwt默认是不加密的,当然,也可以自行加密,如在生成原始的Token之后,可以使用密钥再次进行加密;
2、jwt不加密的情况下,不建议将重要信息放置在jwt中。
3、jwt不仅可以用于认证,也可以用于交换信息,有效的使用jwt,可以降低服务器查询数据库的次数,即IO。
4、JWT最大的缺点是:无法在使用过程中废止某个token,或者更改token的权限,也因为服务器不保存session的状态,也就是说,一旦jwt签发,在token到期之前都始终有效,除非服务器更改逻辑,如修改密钥等。
5、jwt本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。因为,为了减少盗用,JWT的有效期应该设置的短一些,对于一些比较重要的权限,使用时,应该再次对用户进行认证。
6、为了减少盗用,JWT不应该使用HTTP协议明码传输,要使用HTTPS协议传输。

五、功能实现

 

 

 

 

 

扫一扫,在手机上查看