目录
4.登陆方法成功后,将生成的JWT令牌通过响应头返回给客户端
一、JWT简介
1.什么是JWT?
JWT(JSON WEBTOKEN):JSON网络令牌,JWT是一个轻便的安全跨平台传输格式,定义了一个紧凑的自包含的方式在不同实体之间安全传输信息(JSON格式)。它是在Web环境下两个实体之间传输数据的一项标准。实际上传输的就是一个字符串。广义上讲JWT是一个标准的名称;狭义上JWT指的就是用来传递的那个token字符串。JSON Web Token (JWT),它是目前最流行的跨域身份验证解决方案
2.为什么要使用JWT?
JWT的精髓在于:“去中心化”,就是数据保存在各个客户端而不是服务器
二、JWT的工作原理
1、客户端通过Web表单将正确的用户名和密码发送到服务端的接口。这一过程一般是POST请求。建议的方式是通过SSL加密的传输(https协议),从而避免敏感信息被嗅探。
2、服务端核对用户名和密码成功后,将用户的id等其他信息作为JWT Payload(负载),将其与头部分别进行Base64编码拼接后签名,形成一个JWT。形成的JWT就是一个形lll.zzz.xxx的字符串,并设置有效时间。
3、服务端将JWT字符串作为登录成功的返回结果返回给客户端。
4、客户端将返回的JWT以cookie的形式保存在浏览器上,并设置cookie的有效时间(建议客户端cookie和服务端JWT的有效时间设置为一致),用户登出时客户端需删除cookie。
5、客户端在每次请求时将JWT放入HTTP Header中的Authorization位。(解决XSS和XSRF问题)
6、服务端对收到的JWT进行解密和校验,如检查签名是否正确、Token是否过期、Token的接收方是否是自己等。
7、验证通过后服务端使用JWT中包含的用户信息进行其他逻辑操作,返回相应结果,否则返回401
三、JWT的组成
JWT由三部分组成:
- Header(头部)
- Payload(负载)
- Signature(签名)
它是一个很长的字符串,中间用点(.)分隔成三个部分。注意,JWT 内部是没有换行的,这里只是为了便于展示,将它写成了几行。
写成一行,就是下面的样子:Header.Payload.Signature
1.Header(头部)
由令牌的类型(typ)和正在使用的签名算法(alg)组成。如:
{"typ":"JWT","alg":"HS256"}
- typ跟alg属性的全称其实是type跟algorithm,分别是类型跟算法的意思。之所以都用三个字母来表示,也是基于JWT最终字串大小的考虑,
- 同时也是跟JWT这个名称保持一致,这样就都是三个字符了…typ跟alg是JWT中标准中规定的属性名称
2.Payload(载荷)
payload用来承载要传递的数据,它的json结构实际上是对JWT要传递的数据的一组声明,这些声明被JWT标准称为claims
载荷的属性有三类:
保留(Registered) 公有(public) 私有(private)
{"sub":"123","name":"Tom","admin":true}
Reserved claims(保留)
它的含义就像是编程语言的保留字一样,属于JWT标准里面规定的一些claim。JWT标准里面定义好的claim有:
- iss(Issuser):代表这个JWT的签发主体;
- sub(Subject):代表这个JWT的主体,即它的所有人;
- aud(Audience):代表这个JWT的接收对象;
- exp(Expiration time):是一个时间戳,代表这个JWT的过期时间;
- nbf(Not Before):是一个时间戳,代表这个JWT生效的开始时间,意味着在这个时间之前验证JWT是会失败的;
- iat(Issued at):是一个时间戳,代表这个JWT的签发时间;
- jti(JWT ID):是JWT的唯一标识。
Public claims(公有)
在使用 JWT 时可以额外定义的载荷。为了避免冲突,应该使用 IANA JSON Web Token Registry中定义好的,或者给额外载荷加上类似命名空间的唯一标识。
Private claims(私有)
这个指的就是自定义的claim,比如前面那个示例中的admin和name都属于自定的claim。这些claim跟JWT标准规定的claim区别在于:JWT规定的claim,
- JWT的接收方在拿到JWT之后,都知道怎么对这些标准的claim进行验证;而private claims不会验证,除非明确告诉接收方要对这些claim进行验证以及规则才行
- 按照JWT标准的说明:保留的claims都是可选的,在生成payload不强制用上面的那些claim,你可以完全按照自己的想法来定义payload的结构,不过这样搞根本没必要:
- 第一是,如果把JWT用于认证, 那么JWT标准内规定的几个claim就足够用了,甚至只需要其中一两个就可以了,假如想往JWT里多存一些用户业务信息,
- 比如角色和用户名等,这倒是用自定义的claim来添加;第二是,JWT标准里面针对它自己规定的claim都提供了有详细的验证规则描述,
- 每个实现库都会参照这个描述来提供JWT的验证实现,所以如果是自定义的claim名称,那么你用到的实现库就不会主动去验证这些claim
3.signature
- 签名是把header和payload对应的json结构进行base64url编码之后得到的两个串用英文句点号拼接起来,然后根据header里面alg指定的签名算法生成出来的。
- 算法不同,签名结果不同。以alg: HS256为例来说明前面的签名如何来得到。
- 按照前面alg可用值的说明,HS256其实包含的是两种算法:HMAC算法和SHA256算法,前者用于生成摘要,后者用于对摘要进行数字签名。这两个算法也可以用HMACSHA256来统称
四、JWT的验证过程
它验证的方法其实很简单,只要把header做base64url解码,就能知道JWT用的什么算法做的签名,然后用这个算法,再次用同样的逻辑对header和payload做一次签名,并比较这个签名是否与JWT本身包含的第三个部分的串是否完全相同,只要不同,就可以认为这个