0%

JWT

JSON Web Token(JWT)是一个非常轻巧的规范。这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。

JWT

JWT有3个组成部分,每部分通过点号来分割 header.payload.signature

  • 头部(header) 是一个 JSON 对象,描述 JWT 的元数据。
    • Jwt的头部是一个JSON,然后使用Base64URL编码,承载两部分信息:
      • 声明类型typ,表示这个令牌(token)的类型(type),JWT令牌统一写为JWT
      • 声明加密的算法alg,通常直接使用HMACSHA256,即HS256
    • 例如:{ "alg": "HS256", "typ": "JWT"}
  • 载荷(payload) 是一个 JSON 对象,用来存放实际需要传递的数据
    • payload也是一个JSON字符串,是承载消息具体内容的地方,也需要使用Base64URL编码,payload中可以包含预定义的7个key,它们不是强制性的,但推荐使用,也可以添加任意自定义的key
      1. iss(issuer): jwt签发者
      2. sub(subject): jwt所面向的用户
      3. aud(audience): 接收jwt的一方, 受众
      4. exp(expiration time): jwt的过期时间,这个过期时间必须要大于签发时间
      5. nbf(Not Before): 生效时间,定义在什么时间之前.
      6. iat(Issued At): jwt的签发时间
      7. jti(JWT ID): jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
    • 例如:{"sub": "1234567890", "name": "John Doe", "iat": 1516239022},该token签发给1234567890,姓名为John Doe(自定义的字段),签发时间为1516239022
  • 签证(signature) 对header和payload使用密钥进行签名,防止数据篡改。
    • Signature 部分是对前两部分的签名,防止数据篡改。
  • 用于签名的密钥是保存在服务器端的,jwt的签发生成也是在服务器端的,密钥secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。
  • 注意客户端发送的Authorization HTTP HEADER格式是 “Bearer YOUR_JWT_TOKEN”,这是OAuth的规范规定的。(加前缀Bearer,空格隔开)
  • jwt.io调试器
  • Base64编码可用于在HTTP环境下传递较长的标识信息。

优点

优点:

  • 多样化的传输方式,可以通过URL传输、POST传输、请求头Header传输(常用)
  • 简单方便,服务端拿到jwt后无需再次查询数据库校验token可用性,也无需进行redis缓存校验(对jwt中的头部和载荷进行签名,与jwt中的签证进行对比)
  • 在分布式系统中,很好地解决了单点登录问题
  • 很方便的解决了跨域授权问题,因为跨域无法共享cookie

缺点

缺点:

  • 无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。
  • JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证
  • 为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输
  • 在退出登录/修改密码时怎样实现JWT Token失效
    • 将 token 存入 DB(如 Redis)中,失效则删除;但增加了一个每次校验时候都要先从 DB 中查询 token 是否存在的步骤,而且违背了 JWT 的无状态原则(这不就和 session 一样了么?)。
    • 维护一个 token 黑名单,失效则加入黑名单中。
    • 在 JWT 中增加一个版本号字段,失效则改变该版本号。
    • 在服务端设置加密的 key 时,为每个用户生成唯一的 key,失效则改变该 key。

SpringBoot整合

Spring Boot集成JSON Web Token(JWT)

B站-编程不良人

SpringSecurity整合

SpringSecurity整合JWT

B站-小明哥

注意事项

  1. 为什么用JWT?

    • JWT只通过算法实现对Token合法性的验证,不依赖数据库,Redis等存储系统,因此可以做到跨服务器验证,只要密钥和算法相同,不同服务器程序生成的Token可以互相验证。
  2. JWT Token需要持久化在Redis中吗?

    • 不应该这样做,这样就背离了JWT通过算法验证的初心。
  3. 在退出登录时怎样实现JWT Token失效呢?

    • 退出登录,只要客户端端把Token丢弃就可以了,服务器端不需要废弃Token。
  4. 怎样保持客户端长时间保持登录状态?

    • 服务器端提供刷新Token的接口,客户端负责按一定的逻辑刷新服务器Token。
  5. 服务器端是否应该从JWT中取出userid用于业务查询?

    • REST API是无状态的,意味着服务器端每次请求都是独立的,即不依赖以前请求的结果,因此也不应该依赖JWT token做业务查询, 应该在请求报文中单独加个userid 字段。(如果用户token泄露的话,只从jwt token里取就可能导致越权
    • 为了做用户水平越权的检查,可以在业务层判断传入的userid从JWT token中解析出的userid是否一致, 有些业务可能会允许查不同用户的数据(那就要规定好当前用户id和待查询用户id所使用的字段名,不要冲突了)。

参考资料:

JWT安全验证常见疑问解答

Java安全验证之jwt(json web token)

SpringBoot+SpringSecurity+JWT实现认证和授权

SpringBoot整合SpringSecurity实现JWT认证

若图片不能正常显示,请在浏览器中打开

欢迎关注我的其它发布渠道