JWT (JSON Web Token)

(1) JWT简介

什么是JWT

  • JWT是一种基于 Token 的****认证授权机制.
  • JWT (JSON Web Token) 是目前最流行的跨域认证解决方案,是一种基于 Token 的认证授权机制。从 JWT 的全称可以看出,JWT 本身也是 Token,一种规范化之后的 JSON 结构的 Token。

JWT有什么用

  • JWT最常见的场景就是授权认证,用户登录之后,后续的每个请求都将包含JWT, 系统在每次处理用户请求之前,都要先进行JWT的安全校验,通过校验之后才能进行接下来的操作.

JWT认证方式

  • JWT通过数字签名的方式,以JSON对象为载体,在用户和服务器之间传递安全可靠的信息.

  1. 首先,前端通过Web表单将自己的用户名和密码发送到后端的接口。这一过程一般是一个HTTP POST请求。建议的方式是通过SSL加密的传输(https协议),从而避免敏感信息被嗅探。
  2. 后端核对用户名和密码成功后,将用户的id等其他信息作为JWT Payload(负载),将其与头部分别进行Base64编码拼接后签名,形成一个JWT(Token)。形成的JWT就是一个形同lll.zzz.xxx的字符串。 token head.payload.singurater
  3. 后端将JWT字符串作为登录成功的返回结果返回给前端。前端可以将返回的结果保存在localStorage或sessionStorage上,退出登录时前端删除保存的JWT即可。
  4. 前端在每次请求时将JWT放入HTTP Header中的Authorization位。(解决XSS和XSRF问题) HEADER
  5. 后端检查是否存在,如存在验证JWT的有效性。例如,检查签名是否正确;检查Token是否过期;检查Token的接收方是否是自己(可选)。
  6. 验证通过后后端使用JWT中包含的用户信息进行其他逻辑操作,返回相应结果。

(2) JWT的组成部分

头部(Header)

  • 描述 JWT 的元数据,定义了生成签名的算法以及 Token 的类型。
1
2
3
4
 {"typ":"JWT","alg":"HS256"}
 
 //typ(Type):令牌类型,也就是 JWT。
 //alg(Algorithm) :签名算法,比如 HS256。

JWT签名算法中,一般有两个选择,一个采用HS256,另外一个就是采用RS256

进行BASE64编码https://base64.us/,编码后的字符串如下:eyJhbGciOiJIUzI1NiJ9

Base64编码:一个对象先由ascii码转化为二进制(7个二进制一组),然后再将它们以6个为一组(不足用0补齐),然后转化为十进制,再通过十进制的数字和base64的码值表相互转换得到对应的字符,最后的base64的结果需要是4的倍数,不足用=补齐

载荷(payload)

载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分

1
 {"sub":"1234567890","name":"John Doe","admin":true}

将上面的JSON数据进行base64编码,得到Jwt第二部分: eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

字段说明,下面的字段都是由 JWT的标准所定义的

1
2
3
4
5
6
7
 iss: jwt签发者
 sub: jwt所面向的用户
 aud: 接收jwt的一方
 exp: jwt的过期时间,这个过期时间必须要大于签发时间
 nbf: 定义在什么时间之前,该jwt都是不可用的.
 iat: jwt的签发时间
 jti: jwt的唯一身份标识,主要用来作为一次性token。

签名(signature)

服务器通过 Payload、Header 和一个密钥(Secret) 使用 Header 里面指定的签名算法(默认是 HMAC SHA256)生成。

Signature 部分是对前两部分的签名,作用是防止 Token(主要是 payload) 被篡改。

这个签名的生成需要用到:

  • Header + Payload。
  • 存放在服务端的密钥(一定不要泄露出去)。
  • 签名算法。

例如,如果要使用HMAC SHA256算法,则将通过以下方式创建签名:

1
2
 String encodeString = base64UrlEncode(header) + "." + base64UrlEncode(payload);
 String secret = HMACSHA256(encodeString,secret);

签名用于验证消息在此过程中没有更改,并且对于使用私钥进行签名的令牌,它还可以验证JWT的发送者是它所说的真实身份。

注意:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。

(3) 签名的目的

最后一步签名的过程,实际上是对头部以及载荷内容进行签名。

一般而言,加密算法对于不同的输入产生的输出总是不一样的。对于两个不同的输入,产生同样的输出的概率极其地小(有可能比我成世界首富的概率还小)。所以,我们就把“不一样的输入产生不一样的输出”当做必然事件来看待吧。

所以,如果有人对头部以及载荷的内容解码之后进行修改,再进行编码的话,那么新的头部和载荷的签名和之前的签名就将是不一样的。而且,如果不知道服务器加密的时候用的密钥的话,得出来的签名也一定会是不一样的。

服务器应用在接受到JWT后,会首先对头部和载荷的内容用同一算法再次签名。那么服务器应用是怎么知道我们用的是哪一种算法呢?别忘了,我们在JWT的头部中已经用 alg字段指明了我们的加密算法了。

如果服务器应用对头部和载荷再次以同样方法签名之后发现,自己计算出来的签名和接受到的签名不一样,那么就说明这个Token的内容被别人动过的,我们应该拒绝这个Token,返回一个HTTP 401 Unauthorized响应。

(4) JWT与Token的区别

Token 和 JWT (JSON Web Token) 都是用来在客户端和服务器之间传递身份验证信息的一种方式。但是它们之间有一些区别。

  • Token 是一个通用术词,可以指代任何用来表示身份的字符串。它可以是任何形式的字符串,并不一定是 JWT。
  • JWT 是一种特殊的 Token,它是一个 JSON 对象,被编码成字符串并使用秘密密钥进行签名。JWT 可以用来在身份提供者和服务提供者之间安全地传递身份信息,因为它可以被加密,并且只有拥有秘密密钥的方能解密。

总的来说,JWT 是一种特殊的 Token,它具有更强的安全性和可靠性。

(5) JWT的优势

  • 简洁(Compact): 可以通过URL,POST参数或者在HTTP header发送,因为数据量小,传输速度也很快
  • 自包含(Self-contained):负载中包含了所有用户所需要的信息,避免了多次查询数据库
  • 因为Token是以JSON加密的形式保存在客户端的,所以JWT是跨语言的,原则上任何web形式都支持。
  • 不需要在服务端保存会话信息,特别适用于分布式微服务。