前言
由于我也只是JWT新手,今天在写一个小项目的时候用到了,就自己整理了一下。如下内容均为自己整理,资料来自官网和标准和少数博客。受限于自身技术水平,和翻译水平,难免有些错误,我已经尽可能避免,还是希望不要误导了别人。
JWT是一种新的认证机制,这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。
传统session面临的问题
- session 每次进行验证,服务器都会做出记录,久而久之服务器压力很大
- 由于记录多保存在服务器上,这意味着用户下次请求还必须要请求在这台服务器上,这也意味着限制了应用的扩展能力。
- 可能受到CSRF攻击
token
Token验证是无状态的(stateless),并不需要在服务器上储存,所以解决了session可能面对的一些问题
JWT
一个JWT实际上是一个字符串由三部分构成 头部(header) 载荷(Payload) 和 签名(signature) 根据官方标准
header
部用于描述关于该JWT的最基本的信息,例如其类型以及签名所用的算法等,也可以被表示成一个JSON对象。1
2
3
4{
"typ": "JWT",
"alg": "HS256"(这里表示算法是HS256)
}
经过Base64编码之后得到eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 这就是JWT的header
Tips: Base64只是一种编码形式,不是加密
Payload
载荷就是存在有效信息的地方, There are three types of claims: registered, public, and private claims. 载荷有三种类型
Registered claims(注册声明)—推荐使用,但不是必须 [来源][https://tools.ietf.org/html/rfc7519#page-9]
- iss (issuer) 该JWT的签发者
- exp (expiration time) 什么时候过期,Unix时间戳
- sub (subject) 该JWT所面向的用户
- aud (audience) 接收该JWT的一方
- “iat” (Issued At) jwt的签发时间
- others
Public claims
我们所建立的公开资讯例如使用者姓名,不建议存放敏感信息
Private claims
发行者与订阅者自行沟通定义的Claims Name 与资料,Private Claim Names are subject to collision and should be used with caution.
不建议存放敏感信息
eg:1
2
3
4
5{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
经过base64编码之后 成为JWT的第二部分1
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
Signature
将上面的两个编码后的字符串都用句号.连接在一起(头部在前),就形成了eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
最后,我们将上面拼接完的字符串用HS256算法进行加密。在加密的时候,我们还需要提供一个密钥(secret)。如果我们用secret作为密钥的话,那么就可以得到我们加密后的内容假设是TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ(这里我没跑程序,假设了一个值)1
2
3
4HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
最后把这三个部分用.链接就构成了JWTeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
适用场景
JWT适合用于向Web应用传递一些非敏感信息。例如在完成加好友的操作,还有诸如下订单的操作等等。
不应该在jwt的payload部分存放敏感信息,因为该部分是客户端可解码的部分。
再次强调base64是编码而非加密,所以直接解码直接可以拿到信息了。
结语
翻译查资料搞了挺久,自己收获很大,使用的话明天再说了…如有错误,欢迎指出,感谢阅读!