About JWT(JSON Web Token)
JSON Web Token(JWT)是目前使用广泛的跨域认证解决方案,苯人因一知半解而错误使用而对此稍稍有所了解。
这玩意是个啥
JSONweb token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
为什么要有JWT
这需要提到基于token的身份认证和传统的session认证的区别
传统的session认证
访问网站是使用的http协议本身是无状态的,这就意味着如果用户需要进行身份认证,那么在下一次请求就需要再一次提交认证请求,而服务器必须存储用户登录的信息
这就意味着用户数量过高会使服务器无法承受访问压力
问题
- Session: 用户经过我们的应用认证之后,都要在服务端做一次记录,从而分辨用户,通常而言session都是保存在内存中,而随着认证用户的增多,服务端的开销会明显增大。
- 扩展性: 用户认证之后,服务端做认证记录,如果认证的记录被保存在内存中的话,这意味着用户下次请求还必须要请求在这台服务器上,这样才能拿到授权的资源,这样在分布式的应用上,相应的限制了负载均衡器的能力。这也意味着限制了应用的扩展能力。
- CSRF: 因为是基于cookie来进行用户识别的, cookie如果被截获,用户就会很容易受到跨站请求伪造的攻击。
基于Token的鉴权
虽然也是无状态的协议,但是不需要服务端去保留用户的认证信息,从而降低了服务器的压力同时提高了拓展能力
流程
- 用户使用用户名密码来请求服务器
- 服务器进行验证用户的信息
- 服务器通过验证发送给用户一个token
- 客户端存储token,并在每次请求时附送上这个token值
- 服务端验证token值,并返回数据
关于JWT
格式
JWT是由三段信息通过.
连接组成的字符串
1 | eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ |
如何构成
第一段被称为头部(header),第二段被称为载荷(payload),第三段称为(signature)
header
这里承载了JWT的元数据,例如
1 | { |
再对此使用Base64URL进行加密成为以下的样子
1 | eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9 |
payload
顾名思义,它承载了有效信息,除一些私有字段外,JWT官方规定了7个字段可供选用
- iss (issuer):签发人
- exp (expiration time):过期时间
- sub (subject):主题
- aud (audience):受众
- nbf (Not Before):生效时间
- iat (Issued At):签发时间
- jti (JWT ID):编号
不过JWT默认时没有加密的,所以别把密码什么的私密信息写进去(
我干过)
signature
jwt的第三部分是一个签证信息,这个签证信息由三部分组成:
- header (base64后的)
- payload (base64后的)
- secret
其中的secret是只有服务端才知道,绝对不能泄露,然后使用header中指定的签名算法对其进行加密,以下以SHA256为例
1 | HMACSHA256( |
Base64URL
Base64 有三个字符+
、/
和=
,在 URL 里面有特殊含义,所以要被替换掉:=
被省略、+
替换成-
,/
替换成_
。这就是 Base64URL 算法。
如何使用
一般是在请求头里加入Authorization
,并同时加上Bearer
标注(直接写query里也有):
1 | fetch('~~~~', { |
总结
- 由于JSON的通用性,所以JWT可以被很多语言通用
- 可以在payload中写入一些业务逻辑需要但非敏感的信息
- 利于传输
- 不需要在服务端保存信息,易于拓展