登录流程图

token 是什么

当用户第一次登录后,服务器生成一个 token 并将此 token 返回给客户端,以后客户端只需带上这个 token 前来请求数据即可,无需再次带上用户名和密码。
简单 token 的组成;uid(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名,token 的前几位以哈希算法压缩成的一定长度的十六进制字符串。为防止 token 泄露)。
基于 token 机制的身份认证
使用 token 机制的身份验证方法,在服务器端不需要存储用户的登录记录。大概的流程:

  • 客户端使用用户名和密码请求登录。
  • 服务端收到请求,验证用户名和密码。
  • 验证成功后,服务端会生成一个 token,然后把这个 token 发送给客户端。
  • 客户端收到 token 后把它存储起来,可以放在 cookie 或者 Local Storage(本地存储)里。
  • 客户端每次向服务端发送请求的时候都需要带上服务端发给的 token。
  • 服务端收到请求,然后去验证客户端请求里面带着 token,如果验证成功,就向客户端返回请求的数据。(如果这个 Token 在服务端持久化(比如存入数据库),那它就是一个永久的身份令牌。)

客户端

客户端通过 ajax 发起请求,拦截请求 interceptor ,对请求进行拦截,判断是否存在 token,存在携带请求头发送请求,不存在直接发送请求

1
2
//引入axios
import axios from "axios";
1
2
3
4
5
6
7
8
9
10
11
12
//设置请求拦截器
axios.interceptors.request.use(
(config) => {
if (是否存在token) {
config.headers["token"] = token;
}
return config;
},
(err) => {
return Promise.reject(err);
}
);

服务端

• 判断是否存在白名单内,在直接通过
• 判断是否携带请求头,没携带直接返回无权限
• 判断服务端的 token 是否存在,不存在返回请登录
• 判断时间是否超过规定时间,超过返回登录超时
• 判断请求头的 token 和服务端的 token 是否相同,不相同就返回 token 鉴权被篡改,相同则通过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const { TokenRead } = require("../utlis/index"); //jsonwebtoken解析token数据的函数
const Tg = ["/user/login", "/user/add"]; //白名单
module.exports = (options) => {
return async function tok(ctx, next) {
//判断是否在白名单,存在直接放行
const flag = Tg.includes(ctx.request.url);
if (flag) return await next();

//判断请求是否携带请求头
if (!ctx.request.header.token)
return (ctx.body = { code: 0, msg: "无权限登录" });
//判断服务端的token是否为空
if (ctx.session.token === "" || ctx.session.token === null)
return (ctx.body = { code: 0, msg: "请先登录" });
//判断是否超时
let { data } = TokenRead(ctx.session.token);
if ((new Date().getTime() - data) / 1000 / 60 / 60 > 2)
return (ctx.body = { code: 0, msg: "时间到期,请重新登录" });
//判断token是否被篡改
if (ctx.session.token != ctx.request.header.token) {
return (ctx.body = {
code: 0,
msg: "token被篡改",
});
}
await next();
};
};