文章不保证最新,最新版请到博客 www.huborui.com 查看。
JSON Web Token
是一个非常简单实用的规范,通过它可以在客户端和服务端之前传递安全可靠的数据。
jwt 由三部分组成:
- 头部(header)
- 载荷(payload)
- 签名(signature)
将这三部分用 .
连接起来就构成一个 jwt(header.payload.signature
)。
下面就通过这三个部分道出从 jwt 生成到获取数据的原理。
header
header 描述 jwt 的基本信息,如类型、签名所用算法等。
{
// 类型为 JWT
"typ": "JWT",
// HS256 算法
"alg": "HS256"
}
复制代码
对 header 进行 Base64
编码,得到第一部分。
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
复制代码
没错,Base64 编码并不是加密方式,可以还原的!不加密我们的 jwt 还安全么?继续看下去。
payload
payload 是携带数据的地方,我们可以将需要传递到服务端的数据放在 payload 内。
既然我们的宝贝数据放在 payload,那它会不会被加密?
不会!还是 Base64 编码,可以还原的!所以不要往里面放贵重的数据。
{
// 官方定义了 5 个字标识一些信息
// jwt 签发者
"iss": "god",
// 在什么时候签发
"iat": 1441525213,
// exp 什么时候过期 Unix 时间戳
"exp": 1441525324,
// 接收 jew 的用户
"aud": "[email protected]"
// jwt 面向的用户
"sub": "[email protected]"
// 剩下的就可以自己定义了
"userID": 12345,
...
}
复制代码
依旧 Base64 编码,得到第二部分的字符串和 header 用 .
拼在一起。
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcm9tX3VzZXIiOiJCIiwidGFyZ2V0X3VzZXIiOiJBIn0
复制代码
别急,是不是觉得都是明文的数据,服务器如何判断 jwt 的真假呢?下面就到了签名加密环节。
signature
在签名环节,我们需要提供一个只有你知道的密钥(secret),对连在一起的 header 和 payload 用 HS256
算法加密,得到加密后的字符串,和前面的拼在一起:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcm9tX3VzZXIiOiJCIiwidGFyZ2V0X3VzZXIiOiJBIn0.rSWamyAYwuHCo7IFAgd1oRpSP7nzL7BF5t7ItqpKViM
复制代码
三部分合体成功!jwt 构造成功!
防伪
是否能伪造 jwt 呢?仔细想想就知道,如果你不知道服务端的密钥,手动修改 header 或 payload 的任何部分,得到的 Base64 编码就不一样了,新的编码经过密钥生成的签名肯定和旧的不同。没有正确的签名,服务器会直接返回错误。
服务器验证一个 jwt 的过程也很简单:
- 收到 jwt
- 将 header 和 payload 用密钥和对应的算法签名
- 判断生成的签名和 jwt 第三部分是否一致
- 不一致则返回错误,一致则表示 payload 内的数据可信
总结
jwt 的核心就是密钥,拥有密钥就拥有生成 jwt 的权利(千万不能泄露)。
payload 中的数据不是加密的,不要放敏感数据。
参考资料
- JSON Web Token - 在Web应用间安全地传递信息
- 八幅漫画理解使用JSON Web Token设计单点登录系统