如何实现 jwt 鉴权机制?

273 阅读2分钟

JWT(JSON Web Token),本质就是一个字符串书写规范,作用是用来在用户和服务器之间传递安全可靠的信息。

jwt 鉴权的作用

我们在前端通过路由导航配置了路由的权限,但是对应的后端接口依然是可以直接发送请求的,所以我们需要通过 jwt 鉴权来判断接口是否可以发送请求。

jwt 鉴权主要包括两个方面:

  1. 用户登录之后的鉴权设置

  2. 登录状态过期的验证

前端实现思路

用户登录之后的鉴权设置

当我们登录成功之后,后端会返回一个 token,我们把这个 token 存储到浏览器中。在每次发送请求之前判断请求头里是否存在 token,如果请求头里没有 token 且可以从浏览器中获取到 token 值,则说明用户已登录,这时给请求头设置 token 值。

// 登录成功保存 token
login({ username, password }).then((res) => {
  window.localStorage.setItem("token", res.token);
})
// 请求拦截器
service.interceptors.request.use(
  (config) => {
    const token = window.localStorage.getItem("token");
    if (!config.headers.Authorization && token) {
      config.headers.Authorization = "Bearer " + token;
    }

    return config;
  },
  (error) => {
    Promise.reject(error);
  }
);

登录状态过期

如果后端判断登录的状态已过期,即 token 值过期,会返回 401,前端就可以在响应拦截器里面做一些处理操作,例如移除 token,跳转到登录页重新登录。

service.interceptors.response.use(
  (res) => {
    const code = res.data.code || 200;
    const msg = res.data.msg;

    if (code === 401) {
      if (!isRelogin.show) {
        isRelogin.show = true;
        // 弹出提示框
        MessageBox.confirm(
          "登录状态已过期,您可以继续留在该页面,或者重新登录",
          "系统提示",
          {
            confirmButtonText: "重新登录",
            cancelButtonText: "取消",
            type: "warning",
          }
        )
          .then(() => {
            isRelogin.show = false;
            // 删除保存在浏览器里的 token
            window.localStorage.removeItem("token");
            location.href = "/index";
          })
          .catch(() => {
            isRelogin.show = false;
          });
      }
      return Promise.reject("无效的会话,或者会话已过期,请重新登录。");
    }
    return res.data;
  }
);

后端实现思路

Node.js 中我们可以使用 jsonwebtoken 包来生成及校验 token

// 1. 导入包
const jwt = require('jsonwebtoken')

// 2. 定义密钥
const KEY = 'qwerty'

// 3. 定义载荷
const data = { username: '' }

// 4. 生成 token
const token = jwt.sign(data, KEY, {
  expiresIn: 60, // 设置过期时间
})

// 5. 校验 token 是否过期
jwt.verify(token, KEY, (err, data) => {
  if (err) {
    console.log('校验失败')
    return
  }
  console.log(data)
}

用户登录之后的鉴权设置

用户验证通过之后生成 token,然后返回该 token

const jwt = require('jsonwebtoken')

const KEY = 'qwerty'

router.post('/login', (req, res) => {
  // 用户验证通过
  const token = jwt.sign({ username: req.body.username }, KEY, { expiresIn: 60 })
})

登录状态过期

添加一个全局的路由中间件,判断 token 值是否过期

const jwt = require('jsonwebtoken')

const KEY = 'qwerty'

// 注册路由中间件
app.use((req, res, next) => {
  const token = req.get('authorization').split(' ')[1]
  // 判断是否登录
  if (!token) {
    res.json({
      code: 500,
      msg: '验证不通过',
    })
  } else {
  // 验证 token 是否过期
  jwt.verify(token, KEY, (err, data) => {
    if (err) {
      res.json({
      code: 401,
      msg: '登录已过期',
    })
    return
  }
  // 保存用户信息
  req.user = data
  next()
  })
 }
})