1. 为什么有JWT?
服务器端维护登录状态,使用传统Cookie和Session方案,扩展性不好。而JWT可实现服务器无状态,扩展性好。
在单点登录的时候,共享登录状态信息的实现有以下两种方案:
- 方案一:使用session 数据持久化(写入数据库或者Redis中),服务受到请求后,向持久层请求数据,但如果持久层挂了,就会单点失败。
- 方案二:使用JWT,服务器不保存session数据,所有状态信息都保存在客户端,每次请求都发回服务器。
2. JWT是什么?
JSON Web Token(JWT)是一个开放标准(RFC 7519),它定义了一种紧凑且独立的方式,用于在各方之间作为JSON对象安全地传输信息。 此信息可以通过数字签名进行验证和信任。 JWT可以使用HMAC对称加密算法或RSA (ECDSA) 非对称加密算法进行签名。
3. 实现原理?
服务器认证以后,生成一个json对象,发回给客户端。之后,客户端与服务端通信,回传这个JSON对象。服务器靠这个对象认定用户身份。为防止用户篡改数据,服务器生成这个对象的时候,会加上签名。服务器不再保存任何session数据,实现了服务无状态,从而比较容易实现扩展。
4. JWT长什么样?
Header.Payload.Signature
- Header:经Base64URL算法转成字符串的JSON对象,描述JWT的元数据,如签名算法(默认HMAC SHA256 对称加密)、令牌类型等属性
- Payload:经Base64URL算法转成字符串的JSON对象,实际传输的数据,如签发人iss、主题sub、受众aud、过期时间exp、生效时间nbf、签发时间iat、编号jti (7个官方字段)以及自定义私有字段
- Signature:对前两部分的签名,指定密钥secret ,对头部以及载荷内容进行签名。如果有人对头部以及载荷的内容解码以后进行修改,再进行编码的话,即时使用相同密钥签名,结果也与原来的不一样。如果不知道服务器加密时候用的秘钥的话,得出来的签名也是不一样的。
Base64URL算法
Base64编码后的字符串中可能包含 + 、/ 和 = 三个字符,在 URL 里面有特殊含义,所以要被替换掉:= 被省略、+ 替换成-,/ 替换成 _ 。这就是 Base64URL 算法。
JWT作为一个令牌(token),有些场景可能会放到URL(如:api.example.com/?token=xxx),因此需要采用Base64URL 算法将Header 和 Payload 转化为字符串。
5.存储位置?
JWT可选择的客户端存储位置包括sessionStorage、localStorage和cookie。三个位置各有优缺点,具体比较如下。
sessionStorage | 浏览器关闭即自动清除数据 | 存在不可跨浏览器窗口共享数据,跨窗口需重新登录;可被JS读取,可能受到XSS攻击 |
localStorage | 可跨窗口共享数据,过期时间前可实现自动登录 | 退出登录或JWT过期需主动清除数据;可被JS读取,可能受到XSS攻击 |
cookie | 可设置httpOnly属性防止被JS读取,防止XSS攻击;可设置secure保证JWT只在HTTPS下传输 | 容易受到CSRF攻击 |
Token的初衷是防范CSRF攻击。防范大概的原理是,cookie会被浏览器自动带上,而token 或 JWT需要在发送请求前,前端代码中去设置请求头,防范了CSRF的攻击。XSS攻击的防范比较容易,因此笔者个人不推荐将JWT存在cookie里(个人意见,不喜勿碰)。
6.JWT的优点和缺点
优点:
- 所有状态信息存储在客户端,减轻了服务端压力
- JWT不仅可以用于认证,也可以用于交换信息。有效使用JWT,可以降低服务器查询数据库的次数
缺点:
- 使用过程中无法废止或修改,签发后到期前始终有效
- 包含认证信息,泄露后权限被盗用 (针对该问题,建议采用较短的有效期,并使用HTTPS协议传输)
- 续签问题
7.使用过程中JWT失效怎么办?
如果在用户使用过程中,JWT失效(过期时间到了),页面跳转至登录页,这样会造成不好的用户体验。
- 解决方案1:Refresh Token。服务器端token过期,通知客户端,客户端使用Refresh Token重新申请一个全新的JWT使用。
- 解决方案2:将过期时间设置为深夜,比如凌晨3、4点,这样出现操作中token过期的可能性就极小了。该方案主要针对TO B业务。不过,即使是TO C的业务,凌晨3、4点使用的可能性也较小,真的碰上了登录一下好像也可以理解。
关于Token
从范围来讲,JWT属于Token,Token的形式可以多种多样,不限于JWT这种Header.Payload.Signature样子。JWT的特点大部分都适用于Token,当然Token也有自己的特性,本文(本次讨论)没有详细讨论Token相关内容,感兴趣的小伙伴可以自行发掘。