JWT 全称是JSON Web Token, 是目前最流行的跨域认证解决方案,是一种基于 Token 的认证授权机制。根据它的名字,可以知道它也是Token的一种,不过是经过大家统一规范化后的。
JWT一共有三部分组成,分别是
Header : 描述 JWT 的元数据,定义了生成签名的算法以及 Token
的类型。
Payload : 用来存放实际需要传递的数据
Signature(签名) :服务器通过 Payload、Header 和一个密钥(Secret)使用 Header 里面指定的签名算法(默认是 HMAC SHA256)生成。
Header 通常由两部分组成:
typ
(Type):令牌类型,也就是 JWT。
alg
(Algorithm) :签名算法,比如 HS256。
示例:
{
"alg": "HS256","typ": "JWT"
}
Payload 也是 JSON 格式数据,其中包含了 Claims(声明,包含 JWT 的相关信息)。
Claims 分为三种类型:
Registered Claims(注册声明) :预定义的一些声明,建议使用,但不是强制性的。
Public Claims(公有声明) :JWT 签发方可以自定义的声明,但是为了避免冲突,应该在 IANA JSON Web Token Registryopen in new window 中定义它们。
Private Claims(私有声明) :JWT 签发方因为项目需要而自定义的声明,更符合实际项目场景使用。
下面是一些常见的注册声明:
iss
(issuer):JWT 签发方。
iat
(issued at time):JWT 签发时间。
sub
(subject):JWT 主题。
aud
(audience):JWT 接收方。
exp
(expiration time):JWT 的过期时间。
nbf
(not before time):JWT 生效时间,早于该定义的时间的 JWT 不能被接受处理。
jti
(JWT ID):JWT 唯一标识。
示例:
{
"iss": "wx",
"iat": 15322232,
"sub": "1234567890",
"name": "John Doe",
"exp": 15323232,
"iat": 1516239022,
"scope": ["admin", "user"]
}
注意:
Payload 部分默认是不加密的,一定不要将隐私信息存放在 Payload 当中!!!
1.4
SignatureSignature 部分是对前两部分(header,payload)的签名,作用是防止 JWT(主要是 payload) 被篡改。
这个签名的生成需要用到:
Header + Payload。
存放在服务端的密钥(一定不要泄露出去)。
签名算法。
签名的计算公式如下:
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.
)分隔,这个字符串就是 JWT。
因为别人用所以我就用?NoNoNo,新东西的产生总是为了解决遇到的问题,具体的问题有以下几点。。。
1.最开始,我们一般都是采用session和cookie的方式,在服务器中单独开辟一部分空间来保存session,平时进行请求时,将cookie携带到请求头中发送到后台,服务端通过这JSESSIONID判断是哪一个session,通过这样来进行登录验证。但是随着用户的不断增多,用户信息直接保存在服务端内存中,内存开销太大。
2. 如果只有一个服务器,那么它就是单机项目, 用户信息直接保存在那个唯一的服务器中。但是当如果有多个服务器(分布式)的时候,怎么保证其它的服务器也有我存储的信息呢,所以在多台服务器无法正确拿到session信息。
3.用户可以直接看到cookie信息, 不安全,容易受到CSRF攻击(跨站请求伪造攻击),比如可以直接通过cookie登录百度网盘,通过cookie+爬虫获取很多需要登录的网站的信息包含的信息太单一, 只有JSESSIONID。
JWT就很好的解决了上述的三个问题。JWT 自身包含了身份验证所需要的所有信息,因此,我们的服务器不需要存储 Session 信息。这显然增加了系统的可用性和伸缩性,大大减轻了服务端的压力。而且使用 JWT 认证可以有效避免 CSRF 攻击,因为 JWT 一般是存在在 localStorage 中,使用 JWT 进行身份验证的过程中是不会涉及到 Cookie 的。
例子:为什么要使用JWT(举例理解)
有一家蛋糕店,在开业的时候,为了进行推广,就给来蛋糕店买蛋糕的用户,每人办了一张会员卡,通过积累消费的次数,可以换取一些小礼品。有一名用户办理了会员卡(session),老板就在它小本本(服务器特定空间)上记录一次。随着生意越来越好,老板决定开分店了。但是随着办理会员卡的用户越来越多了,小本本不够了。而且每次找用户的信息,还要去重新查找一遍,很麻烦,而其因为小本本只有一份,其他的分店也不能确认用户是不是会员,于是老板左思右想终于想出来了一个办法:自己设计了一款vip卡片(JWT)利用老板和客户的信息组成了独一无二的vip卡片,发给用户自己保管,只要是用户本人拿着这张卡片,去到任何一个分店进行消费,都知道他是会员,而且也不怕其他人拿着vip卡片去消费。
用户向服务器发送用户名、密码以及验证码用于登陆系统。
如果用户用户名、密码以及验证码校验正确的话,服务端会返回已经签名的 Token,也就是 JWT。
用户以后每次向后端发请求都在 Header 中带上这个 JWT 。
服务端检查 JWT 并从中获取用户相关信息。
1.服务器的秘钥非常重要,通常我们生产环境会有一个KMS(密钥管理系统:Key Management Service,KMS)来管理秘钥,不在程序的配置文件里泄露秘钥。
2.使用安全系数高的加密算法。
3.不要将隐私信息存放在 Payload 当中。
4.Payload 要加入 exp
(JWT 的过期时间),永久有效的 JWT 不合理。并且,JWT 的过期时间不易过长。
SpringBoot具体集成JWT,看下一篇