0%

身份认证之JWT

JWT(JSON Web Token)——一种基于Token的认证授权机制

abstract.png

基本原理

JWT(JSON Web Token)由下述三部分内容组成:

  • header:其是一个描述元信息的JSON对象。其中:alg字段表示签名算法,值默认为HS256,即 HMAC SHA256算法;typ字段表示Token类型,值通常为JWT
  • payload:其是一个用于存放传递信息的JSON对象。官方提供了下述的标准字段,可供选用。当然也可以使用自定义的字段。比如用户名、角色名,以满足实际项目业务的需求
    • jti:该JWT的唯一ID
    • sub:主题。用于标识该JWT所面向的用户或实体。例如:用户ID、设备ID等
    • iss:签发者。例如:签发该JWT的应用服务名
    • aud:接收方。例如:使用该JWT的应用服务名
    • iat:签发时间。一般为秒级的Unix时间戳
    • exp:过期时间。一般为秒级的Unix时间戳
    • nbf:生效时间。一般为秒级的Unix时间戳
  • signature:服务端使用header中alg字段指定的签名算法,按照下述规则对header、payload进行签名
1
2
3
4
# 签名计算规则,其中:
# base64UrlEncode 为 Base64URL 编码
# secret 为服务端保存的密钥,不可泄露
signature = HMACSHA256( base64UrlEncode(header)+"."+base64UrlEncode(payload), secret)

JWT最终其实是一个形如xxx.yyy.zzz的字符串。其拼接规则为 将header进行Base64URL编码后的字符串、payload进行Base64URL编码后的字符串、signature三部分拼接起来,并使用 . 符号进行分隔

1
2
# JWT的拼接规则
JWT字符串 = base64UrlEncode(header) + "." + base64UrlEncode(payload) + "." + Signature

所以,不要在JWT的header、payload中包含任何敏感隐私信息。因为一般情况下header、payload中的内容是不加密的。所以当我们拿到一个JWT字符串后,只需分别对xxx、yyy进行Base64URL解码,即可获取到header、payload的内容了

使用场景

传统的基于Session-Cookie的认证方案,存在诸多缺陷、不便:

  • 服务端存储、管理大量的Session信息,增加存储开销
  • 拓展性差,需通过session共享同步等机制来实现水平拓展
  • 客户端禁用Cookie后,传统的Session-Cookie认证机制无法work。虽然客户端侧的开发同学可以通过手动管理、存储、传递SessionID的方式来解决,但这增加了客户端侧开发工作的复杂度
  • Cookie存在跨域问题
  • 不适合移动端场景

而基于JWT的认证方案则优势明显:

  1. JWT是无状态的,拓展性好
  2. 支持跨域
  3. 适合移动端场景

当然该方案的缺点也不是没有:

  • 撤销问题:由于JWT的无状态性,一旦签发无法直接立即撤销,除非过期。为此可以考虑引入黑名单机制。具体地:撤销某JWT时将其唯一ID(jti字段的值)记录到黑名单中。服务端在验签时如果发现某JWT在黑名单中,则直接验签失败。虽然该机制打破了JWT的无状态性,但安全性大大提升了。必要时可以考虑使用
  • JWT字符串长度较大

这里介绍使用JWT进行认证的基本流程:

  1. 用户首次登陆系统通过用户名、密码等信息进行登陆
  2. 服务端对登陆信息校验成功后,向客户端签发、返回JWT
  3. 客户端收到JWT后,可以存储在cookie 或 localStorage 当中。这样用户后续操作时,客户端即可以在请求中携带该JWT到服务端
  4. 服务端在收到客户端的后续请求时会先进行验签,只有验签成功才会执行下一步操作。具体验签流程:
    1. 从请求携带的JWT解析出header、payload、signature三部分
    2. 利用 secret 和 解析出的header、payload 计算一个新的签名
    3. 对比 解析出的signature 和 计算出的签名 是否一样。如果一样,则证明header、payload中的内容没有被篡改,验签成功;反之验签失败

Note

  • 如果JWT未进行加密,则不要在JWT的header、payload中包含任何敏感隐私信息
  • JWT需要使用exp过期时间机制,服务端需要拒绝过期的JWT。永久有效的JWT不仅不合理,而且非常危险
  • 服务端在计算签名、验证签名过程中所使用的secret不可以泄露。例如:不能在服务端代码中硬编码、不可存储到代码的VCS版本控制系统等
  • 使用HTTPS协议,避免通信过程中JWT被窃取、截获
  • 可在 https://jwt.io 网站上对JWT字符串进行在线解码。得到header、payload部分的明文,并验证signature签名
  • Base64URL编码 与 Base64编码 的区别:
    1. Base64URL编码将Base64编码中的 + 替换为 - ,将 / 替换为 _ 。因为 +/ 在URL中分别表示空格、用于路径分隔
    2. 通常Base64编码会使用 = 符号来填充缺失的字节,以确保最终输出长度是4的倍数。而Base64URL编码则不进行填充,以保证URL的简短
请我喝杯咖啡捏~
  • 本文作者: Aaron Zhu
  • 本文链接: https://xyzghio.xyz/JWT/
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-ND 许可协议。转载请注明出处!

欢迎关注我的微信公众号:青灯抽丝