一文了解JWT
Our-task介绍
本篇博客是我github上our-task:一个完整的清单管理系统的配套教程文档,这是SpringBoot+Vue开发的前后端分离清单管理工具,仿滴答清单。目前已部署在阿里云ECS上,可进行在线预览,随意使用(附详细教程),大家感兴趣的话,欢迎给个star!
一文了解JWT
介绍
JWT(Json Web Token)是目前最流行的跨域认证解决方案。它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。
跨域认证的问题
传统认证流程
- 用户在浏览器输入用户名和密码提交,浏览器把用户名和密码发送到服务器。
- 服务器验证通过后,在当前会话(session)中保存相关数据,例如用户的名称、登录时间等等。
- 服务器向浏览器返回一个session_id,写入用户的cookie。
- 之后用户发起的每一次请求,都会通过cookie,将session_id传回服务器。
- 服务器收到session_id,找到之前保存的信息,从而得出用户的身份。
存在问题
在这种认证模式下存在的主要问题就是扩展性不好。单机肯定是没有问题的,但是如果存在多台服务器的集群的话,就要求session能够实现数据共享。
举例来说:我们有A、B、C三台服务器,用户在服务器A中进行登录,由于负载均衡的影响,该用户的下一次请求,可能会由服务器B处理,但是此时服务器B并没有存储用户登录的信息,于是用户又需要重新登录一次,这对用户来说当然是不能忍受的。
解决方案
- 一种方案是session数据持久化,把该session存储到数据库中,每个服务器在收到请求后,都需要向数据库请求数据。这种方案优点是架构清晰,缺点是工程比较大,毕竟每次都需要去请求数据库。
- JWT的方案就是:不让服务器保存session了,把所有的数据都保存在客户端,每次请求的时候,都把这些数据连同请求一起发送给服务器进行验证。
JWT详细介绍
无状态
由于服务器不保存任何session数据,从此服务器就变成无状态的了,从而容易实现扩展。
eyJhbGciOiJIUzUxMiJ9.eyJleHAiOjE2MDc5MzMxMTcsInN1YiI6InVzZXIiLCJjcmVhdGVkIjoxNjA3OTI5NTE3ODQ4fQ.0VoICWN3FTCaFqtJ4q8zHk-K1jfWV-kJ8yRNYiWuvHcOX9kr8dKbHzPHIzG0WyvOmoNa0IN4B4QooX7hwZJraQ
JWT是一个很长的字符串,并且是没有换行的,另外,它由三部分组成,中间会有两个小点,类似:xxx.xxx.xxx这种形式。三个部分依次是:Header(头部)、Payload(负载)、Signature(签名)。
Header(头部)
Header部分是一个JSON对象,描述JWT的元数据,通常是下面的样子
{
"alg":"HS256",
"typ":"JWT"
}
上面的代码中,alg属性表明签名用的算法,默认是:HMAC SHA256,写为:HS256,typ属性表示这个令牌的类型,JWT令牌统一写为:JWT。
Payload(负载)
Payload部分也是一个JSON对象,用来存放实际需要传递的数据。JWT规定了7个官方字段:
- iss(issuer):签发人
- exp(expiration time):过期时间
- sub(subject):主题
- aud(audience):受众
- nbf(Not Before):生效时间
- iat(Issued At):签发时间
- jti(JWT ID):编号
除了官网字段,我们也可以自定义字段,比如:
- name:"xxx"
- age:18
不过需要注意的是,JWT默认是不加密这段的,任何人都可以读取到,所以不要把秘密的信息放在这里。
Signature(签名)
这部分是对前两部分的签名,防止数据篡改
首先,需要指定一个密钥,这个密钥只有服务器才知道,不能泄露给用户。
然后针对Header、Payload、Signature进行签名,把三个部分拼成字符串,每个部分点(.)分隔,返回给用户。
可以通过以下方式创建签名
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
JWT的使用方式
客户端收到服务器返回的JWT,可以存储在Cookie里面,也可以存储在localStorage里面。
之后,客户端每次请求服务器,都要带上JWT。可以把它放在Cookie里面自动发送,但是这样不能跨域。所以更好的做法是放在HTTP请求的头部信息Authorization字段里面。
另一种做法是,跨域的时候,JWT就放在POST请求的数据体里面。