一文读懂 JWT

image.png

什么是 JWT

JWT 全称为 JSON Web Token 是一种在跨域时验证用户的一种措施。

javascript

JWT 与 传统 COOKIE SESSION 的区别是什么?

首先咱们来回想一下传统 cookie session 的验证流程
html

  1. 客户端登录帐号
  2. 服务端接受到用户信息,验证帐号密码,签发一个 sessionId,以 cookie 的方式的返回给客户端存储
  3. 每当下次请求的时候,客户端就会携带上同域名的 cookie,里面就有 sessionId,以此标识用户身份。


这样会有一个问题,若是 网站A 和 网站B 都是同一家公司。如今要求,网站A 登录了,网站B 也自动登录,请问怎么实现?

一种是 Session 持久化,写入数据库或者其余持久层(好比 redis),各类服务收到请求后,都向持久层请求数据,这种模式架构清晰,可是工程量大,且万一持久层失效,单点登录就会失效。

一种则是服务器直接放弃存储 session 数据了,直接将信息存在客户端。**JWT **就是这种方案的一个表明

java

JWT 原理

JWT 的原理是,服务器认证之后,生成一个 JSON 对象发送给客户端,大概长这样。
node

{
  "name": 'cjfff', 
  "role": "admin",
  "ita": "认证时间"
}
复制代码


日后在通讯过程当中,每次客户端请求都带上,以识别身份。

可是为了防止数据被擅改,会加入签名信息(Signature)。

git

JWT 的数据结构

组成部分

实际的 JWT 是图示这个样子。

github

image.png

这里对数据进行了手动回车换行,方便你们下面复制对比。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJyb2xlIjoiYWRtaW4iLCJuYW1lIjoiY2pmZmZmIiwiaWF0IjoxNTE2MjM5MDIyfQ
.D7OUQ7tygm9PDjXeroA0w3dV4G0Swcbju0jHkS7Hqww
复制代码


能够看到分为了三个部分web

  1. header 红色部分
  2. payload 紫色部分
  3. signature 蓝色部分

每一个部分的信息都是怎么来的?

这里先来个帮助函数
redis

const Base64 = {
  encode(str) {
    // first we use encodeURIComponent to get percent-encoded UTF-8,
    // then we convert the percent encodings into raw bytes which
    // can be fed into btoa.
    let repMap = {
      '=': '',
      '+': '-',
      '/': '_'
    }
    return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g,
      function toSolidBytes(match, p1) {
        return String.fromCharCode('0x' + p1);
      })).replace(/(=|\+|\/)/g, (key) => repMap[key])
  },
  decode(str) {
    // Going backwards: from bytestream, to percent-encoding, to original string.
    return decodeURIComponent(atob(str).split('').map(function (c) {
      return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
    }).join(''));
  }
};
复制代码
  1. header 记录着加密算法信息

大概以下,里面记录着 type,alg 就是加密算法, 能够看到,加密后是与开头数据结构中的 header(第一部分是相同的).
算法

Base64.encode(JSON.stringify({
  "alg": "HS256",
  "typ": "JWT"
})) === 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9' // true
复制代码

  1. payload 用户信息以及签发时间


能够看到 payload 信息也是产出一致的。
数据库

Base64.encode(JSON.stringify({
  "role": "admin",
  "name": "cjffff",
  "iat": 1516239022
})) === 'eyJyb2xlIjoiYWRtaW4iLCJuYW1lIjoiY2pmZmZmIiwiaWF0IjoxNTE2MjM5MDIyfQ'
复制代码

  1. Signature 签名


签名的生成规则以下,这里就不作测试了

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)
复制代码


他们三个部分以 . 组合后就是 JWT 总体数据结构。

JWT 安全吗?

JWT 只是为了解决用户会话的问题,大白话就是识别用户身份。

JWT 自己并无进行加密的行为,Signature(签名) 也只是为了别人擅改数据而已,若是数据被抓包,payload(jwt第二部份内容)中若是携带用户敏感信息的话,第三方使用 base64 解密便可得到数据,因此为了安全性而言请使用 https 代替 http。
**
另外就是应该防止加密用的 **secret **泄漏。

安全总结:

  1. 使用 https 代替 http
  2. 防止 secret 泄漏
  3. 能够对 JWT 进行二次加密(须要额外消耗)

JWT 如何过时?

**JWT **在签发的时候会为 **payload **加上一个 iat(issued at) 签发时间。

而后客户端下次发送带上发送给服务端的时候会根据服务端的过时策略进行验证

好比,服务端设置的过时时间是 10h

  1. 服务端接收到 jwt ,解密后得到签发时间
  2. 若是签发时间 + 10h < 当前时间就是过时了


另外就是,若是用户数据被擅改,此时 JWT 应该是属于过时的,但因为 JWT 的机制问题,token 签发后并无相关的废弃策略,只能使用额外的逻辑去对过时的 JWT 进行过时操做,好比将过时的 JWT 维护在 黑名单列表中。

JWT 如何使用?


客户端收到服务端返回的 JWT 后,能够存储在 COOKIE 中,也能够存储在 localStorage 中。

当每次发送请求的时候, 在 headers 加上 Authorization 字段,内容为 Bearer ${jwt} 便可

而后服务端会用上述接收到的信息,拿到 header + payload 为输入数据,进行上面算法生成 Signature 再和 客户端接收到的 Signature 进行对比,一致的话就完成了验证。

JWT Koa2 demo

koa-jwt-demo 地址

参考

  1. 阮一峰 JWT 入门
  2. JWT 官网

## 延伸阅读
  1. jsonwebtoken 源码 里面就是根据上述规则去写的逻辑,感兴趣的能够看看
相关文章
相关标签/搜索