什么是JWT?
JWT全称是JSON Web Token,这是一个开放的RFC7519标准,它定义了在两者之间使用JSON安全传输数据的准则。
传输的数据是可信的,并且是可验证的,因为数据已经添加了数字签名。
签名可以用密钥或者是RSA密钥对签名。
有什么特性呢?
体积比较小,可以作为URL,POST数据等的参数,也可以放在HTTP头里面传输。另一方面,小意味着传输比较快。
里面包含的信息都是可以直接拿来用的,避免了去数据库查询。
什么时候应该使用JWT?
典型场景:
身份验证:这个是JWT最常用的场景了。一旦用户登录,之后的请求都需要带上JWT信息,验证通过之后才能访问授权的资源。比如单点登录,手机APP接口等。
信息交换:因为JWT的数据是签名之后的数据,这样可以保证安全。
JWT的数据结构
由三部分组成,每一个部分是用点(.)分割的:
Header(头);
Payload(数据);
Signature(签名)。
所以,典型的JWT数据格式看起来像这样:xxxxx.yyyyy.zzzzz
;
Header
头部包含两部分,token的类型,固定的JWT;哈希的算法,比如HMAC SHA256或者RSA。
一般hash256的名称是HS256,RSA算法的名称是RS256。
比如:
{ "alg": "HS256", "typ": "JWT"}
然后用base64编码这个JSON,就组成了JWT的第一部分。
Payload
这一部分就包含了我们需要的具体信息(claims)了。
这里的数据又分为三种类型:保留的,公用的和私有的。
保留的: 预先定义的一组数据,不是必须的但是建议有。
比如:iss (issuer), exp (expiration time), sub (subject), aud (audience)等等。
注意,这一部分的数据名称只有三个字符。
公共的: 这一部分的数据是自定义的,但是要避免使用URL和JSON里面的特殊字符。
私有的: 使用双方共享的一些信息。
payload例子:
{ "sub": "1234567890", "name": "John Doe", "admin": true}
这部分数据是我们可以自定义的数据。
然后base64编码数据,作为JWT的第二部分。
Signature
把header和payload分别base64编码之后用点号(.)连接起来,再用header里面指定的算法签名。
如用用HMAC sha256加密:
hash_hmac('sha256', base64UrlEncode(header) . base64UrlEncode(payload), secret);
结果
最后把上面得到的三部分用点号(.)连接起来。
JWT如何工作的?
用户登录后,服务器会返回一个JWT字符串给用户,当访问受保护的资源的时候,需要把这个字符串传回来,验证通过之后才可以访问。
这个和session不同的地方就是,用户登录成功之后不用把认证信息存session,而是直接存在JWT里面,验证的时候从JWT里面解析出来拿来用就可以了。
比较适合用在APP API,单点登录等场景下面。
JWT一般放在HTTP的Authorization头里面,值的前面加上一个Bearer名称,如:Authorization: Bearer <token>
。
下面是一个交互图:
因为JWT是在http协议传输的,也有可能发在url里面,所以base64之后的有些特殊字符需要转换。看下面php实例的base64UrlEncode和base64UrlDecode函数。
PHP代码示例
可以到这里:https://jwt.io/验证结果正确与否。
class Jwt { public function getToken() { $header = $this->base64UrlEncode(json_encode([ 'alg' => 'HS256', 'typ' => 'JWT', ], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); $payload = $this->base64UrlEncode(json_encode([ 'id' => 123, 'name' => 'xiaobai', 'isAdmin' => true, ], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); $secret = '110'; //这里用sha256签名的时候需要返回二进制数据,而不是十六进制字符串,所以第三个参数设置为true $sign = $this->base64UrlEncode(\hash_hmac('sha256', $header . '.' . $payload, $secret, true)); echo "{$header}.{$payload}.{$sign}"; } protected function base64UrlEncode($data) { return str_replace('=', '', strtr(base64_encode($data), '+/', '-_')); } protected function base64UrlDecode($data) { if ($remainder = strlen($data) % 4) { $data .= str_repeat('=', 4 - $remainder); } return base64_decode(strtr($data, '-_', '+/')); } }
本文链接:https://360us.net/article/55.html