JWT 鉴权

JWT 是什么

JSON Web Token(JWT)是一个开放式标准(RFC 7519),它定义了一种紧凑且自包含的方式,用于在各方之间以JSON对象安全传输信息。这些信息可以通过数字签名进行验证和信任。

JWT 的组成

JWT 的格式为 xxx.yyy.zzz。
包含 Header(头部),Payload(负载),Signature(签名)三部分。

  • Header
    通常会声明使用的加密算法和token类型

    1
    2
    3
    4
    {
    "alg": "HS256",
    "typ": "JWT"
    }
  • Payload
    Payload 包含 Claims,Claim是一些实体(一般都是用户)的状态和额外的数据组成。
    JWT 为我们预定义了一些 Claims,例如:iss (issuer), exp (expiration time), sub (subject), aud (audience), and others.
    但是并不要求我们强制使用,我们也可以根据需求自定义 Claim

    1
    2
    3
    4
    5
    {
    "sub": "1234567890",
    "name": "Taven",
    "admin": true
    }
  • Signature

    1
    2
    3
    4
    HMACSHA256(
    base64UrlEncode(header) + "." +
    base64UrlEncode(payload),
    secret)

这段伪代码已经很好的讲解了,签名是如何计算的。服务端提供一个secret,将header、payload 进行base64编码,然后使用header中声明的算法计算签名。

JWT 与 session 对比

  1. 性能:JWT 轻量级,而session 会占用大量服务端内存;
  2. 部署:使用session的系统 负载均衡需要考虑 session 共享,而JWT 不需要;
  3. 安全:安全性的话,小弟不敢多说,我觉得五五开吧,有人说 JWT 泄露的话,直接就可以登录了。但是使用 session 如果请求被拦截了都是一样的;
  4. 场景:APP 中由于没有cookie吧,多是使用token。而 web 应用的话,使用 token 和 session 都是可以的。

实现思路

简单一句话就是,登录之后服务端给客户端颁发JWT,客户端将 JWT 放在请求头中,服务端 filter 校验http header中的JWT。

查阅了一些资料后发现一些分歧

  • 方案1: 有的朋友认为服务端不需要存储 JWT,只在 filter 校验的时候解析无误,即认为 JWT 是可用的。在需要重置 JWT 的时候(例如注销),客户端主动删除JWT。这种做法引发的问题,例如在注销了之后,token 依然可用,由于服务端没有存储 token,无法去校验。于是乎有了方案2

  • 方案2:服务端数据库中存储 JWT,filter 每次校验 token 与数据库中是否一致,这种做法虽然稳妥,但是在性能上一定是不如方案1的。

demo

https://gitee.com/yintianwen7/taven-springboot-learning/tree/master/spring-boot-jwt