ThinkPHP8中使用JWT生成Token和验证Token
网上有很多关于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协议传输。
五、功能实现
- CSS选择器:nth-child()的灵活用法及常见场景示例
CSS选择器中的nth-child()相信大家都比较熟悉,nth-child()和nth-of-type()的区别是:nth-child()不区分类型。大家经常
- 为什么你的logo图模糊不清,移动端图片虚化的解决方案
在传统pc时代的时候,几乎99%的网站都在使用图片格式作为logo,而大部分网站都使用了png透明底的图片来做网站的logo。但是进入移动时代之后,这种习惯还是
- 响应式网站布局的优缺点分析
响应式网站,通俗的讲就是使用CSS媒体查询技术,写一套代码,可以在多个终端上使用。在此之前,前端切图工作者是需要分别针对电脑端、移动端和平板等常见设备专门去写一
- 切图和前端什么关系?为什么前端又被称为切图仔?
很多初从事前端切图这个行业的新人,大多都有一个疑问?为什么要把前端开发人员称为切图仔呢?提起这个问题,我们还要从前端切图行业的发展历程来说起,当然,这个问题对与
- 目前主流的前端框架有哪些?
基本上每种语言都有对应的一些快速框架用于提升开发人员的效率,所谓框架更像是工具箱或者脚手架,在开发时如果能很好的利用框架可以起到事半功倍的效果。简单形象的说,如
- 移动端background-attachment: fixed失效解决方法
在做web前端切图时,我们经常需要做背景图片不跟随内容滚动的效果,这个时候就需要使用到background-attachment: fixed 属性,这个属性及