# 转载请留言联系
什么是JWT?
Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
JWT最普遍的一个作用就是用来保存用户的登录信息。
以前都用session保存用户的登录信息,为什么现在又需要用JWT呢?
-
回顾session
先回顾一下基于session保存用户的登录信息的原理:
session的数据一般存储在redis上,储存的格式一般是这样:
所以,session有什么缺点呢?
- 这种模式最大的问题是,没有分布式架构,无法支持横向扩展。如果使用一个服务器,该模式完全没有问题。但是,如果它是服务器集群或分布式结构的话,则需要一个统一的session数据库库来保存会话数据实现共享,这样负载均衡下的每个服务器才可以正确的验证用户身份。
- sessionid储存在cookies上面的,所以也要做CSRF防护。cookie如果被截获,用户就会很容易受到跨站请求伪造的攻击。
- 单点登录问题:难以适用于单点登录(Single Sign On : 简写SSO)的场景
- 移动开发一般都不使用sessionid来保存登录状态
附:
什么是单点登录(SSO)?
单点登录就是登录一次,可以访问多个不同的子系统(不同的域名)。当你登录了淘宝之后,打开天猫后就自动登录,即使淘宝和天猫是不同的域名。如果没有单点登录的话,你登录了淘宝,再登录天猫,也是需要输入账号密码登录的。
-
JWT的优点
JWT的优点就是能解决上面session的缺点......最重要的是能有效地解决单点登录问题。
-
JWT的验证流程
流程:
1)用户登录成功后,服务器签发jwt,里面储存着用户的id等资料,用于标记用户的登录状态。注意!不能保存敏感信息,例如密码这些,具体原因下面有说。
2)然后在响应报文传送回去给客户端。
3)客户端收到之后,通过html5的 localStorage 或 sessionStorage 来保存JWT。
4)在下一次访问的时候,通过请求头把JWT带上,服务端收到之后,会进行校验,校验有没有修改过啊,有没有过期啊等。
5)校验通过之后,就可以成功登录了。
-
JWT长什么样子?
头部.载荷.签名
JWT示例:
- 头部header
jwt的头部承载两部分信息:
- 声明类型,这里是jwt
- 声明加密的算法,通常直接使用 HMAC SHA256
完整的头部就像下面这样的JSON:
{
'typ': 'JWT',
'alg': 'HS256'
}
然后将头部进行base64编码, 构成了第一部分。
BASE64后的结果:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
-
载荷payload
载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含:
标准中注册的声明 (建议但不强制使用) :
- iss: jwt签发者
- sub: jwt所面向的用户
- aud: 接收jwt的一方
- exp: jwt的过期时间,这个过期时间必须要大于签发时间
- nbf: 定义在什么时间之前,该jwt都是不可用的.
- iat: jwt的签发时间
- jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
其它声明 :比如,用户的相关信息或其他业务需要的必要信息
定义一个payload:
{
"user_name": "John Doe",
"user_id": 10}
BASE64后的结果:
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9注意:payload部分不能存放敏感信息,因为base64是可以解码的。
-
签名signature
JWT的第三部分是一个签证(签名)信息,即对前两部分签名后得到的一个字符串。
签名:使用密钥(SECRECT_KEY )对数据进行加密,得到了一个值(签名)。
签名的作用:防止数据篡改,客户端传给服务器的jwt如果被修改过,服务器验签(校验)会不通过。
// javascript // header和payload部分用.连接起来 var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload); // 使用指定的算法签名 var signature = HMACSHA256(encodedString, 'secret'); // 签名结果: TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ