安全令牌JWT

JWT

前段时间处理一个抽奖H5,测试过程中想到如果有用户抓到抽奖接口,比如

https:xxx/lottery/userinfo
复制代码

如果直接访问抽奖接口,可以直接进行抽奖动作。这里就涉及到处理验证用户身份的问题

之后的解决方式是 判断接口的cookie中是否包含 userInfo 等参数信息

不过还可以通过另外一种方式来处理-- JWT

什么是JWT (JSON WEB TOKEN)

JWT是通信双方之间以 JSON对象的形式安全传递信息的方法。

其实可以理解为使用非对称算法来进行前后端校验。

JWT 由三部分组成

头部

head

  • typ 声明类型

  • alg 声明加密的算法

然后按照此规则将头部信息加密,构成JWT第一部分

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
复制代码

payload

payload 就是存放有效信息的地方

payload

payload 中有一些参数字段是建议使用的 (仅列出几个)

参数 含义
iat jwt的签发时间
exp jwt的过期时间,这个过期时间必须要大于签发时间
nbf 定义在什么时间之前,该jwt都是不可用的

比如来定义一个payload

{
  "exp": Math.floor(Date.now() / 1000) + (60 * 60),
  "name": "John Doe"
}
复制代码

payload 会进行base64加密,构成JWT第二部分

签证

签证

可以看到,签证部分是由三个部分组成的

参数 含义
base64UrlEncode base64加密后的Header
base64UrlEncode base64加密后的payload
your-256-bit-secret 自定义的加密secret

secret 相当于私钥,不可泄漏,如果客户端可以拿到secret,就可以自我签发JWT了

var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload)
var signature = HMACSHA256(encodedString, 'secret')
复制代码

signature 是JWT的第三部分

将以上三部分拼接起来,就是最后的JWT

第三方库

jsonwebtoken

如果自己在生成jwt,有点复杂。目前已经有很多开发的第三方库来支持JWT。比如 jsonwebtoken

jsonwebtoken

  • sign 用于生成 token

  • verify 用于检验token

koa-jwt

koa-jwt 用于验证接口中是否包含token信息

搭建了一个简易的server 来看下效果

项目Git地址

app.use(
  jwtKoa({secret: SECRET})
  .unless({
    path: [/\/login/] // 不需要通过jwt验证的请求路径
  })
)
router.get('/login', async (ctx) => {
  let token = jwt.sign({
    name: 'dva'
  }, SECRET)
  console.log(token, 'token')
  ctx.body = {
    token
  }
})

router.get('/try', async (ctx) => {
  let token = ctx.header.authorization
  let result = jwt.verify(token, SECRET)
  ctx.body = {
    result
  }
})

复制代码
  • /login 拿到token
// {"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiZHZhIiwiaWF0IjoxNTMxMjgwMDg2fQ.Rh_vAKeytjAL2TbOk-MmXQWFesszjRU3Bzldrx5x17s"}%
复制代码
  • 如果不添加token 会被koa-jwt 拦截

wrong

  • 添加 token

token

工作机制

工作机制

图片来自于文章 《前后端分离之JWT用户认证》

  • 登录拿到JWT

  • 前端发起请求,Header中挂载JWT

项目实战

由于我搭建的这个项目中有这种需要鉴权的接口比较少,所以并没有使用koa-jwt来处理。只是用了 jsonwebtoken

项目GIT地址

server端

构建两个接口 login , lottery

server

  • login 用来生成JWT 返回给前端
    token = jwt.sign({
        name: 'who',
        exp: Math.floor(Date.now() / 1000) + (60 * 60), // 设置 token 过期时间
      }, SECRET)
复制代码
  • lottery 用来验证JWT,验证通过则进行抽奖动作
    let token = this.headers.authorization
      // 解码
      let decoded = jwt.verify(token, SECRET)
      // console.log(decoded, 'decoded')
      let {name} = decoded

      if (name != 'who') {
        code = 403
        return
      }
复制代码

前端

  • 首页点击登录后 经返回的token信息存储起来

login

我这里拿到token之后将其写入了localStorage

 window.localStorage.setItem('token', token)
复制代码
  • 进入抽奖页面进行抽奖,每次请求的时候挂载Authorization

Authorization

    axios.get(`/${APP_NAME}/win`, {
      headers: {
        Authorization: token
      }
    })
复制代码

如果传递错误的token 在server端JWT验证的时候就会报错

error

error

项目在线地址

总而言之,如果你的接口需要考虑鉴权问题,可以参考下JWT来处理。

Other

猜你喜欢

转载自juejin.im/post/5b43436e6fb9a04fd26078ab