应用场景:访问某些页面,需要用户进行登录,那我们如何知道用户有没有登录呢,这时我们就可以使用jwt技术。用户输入的账号和密码正确的情况下,后端根据用户的唯一id生成一个独一无二的token,并返回给前端,前端把token保存起来,每次发送请求,请求头携带一个token,以表示用户的身份。当然,后端也要进行校验,确保用户的token不是伪造和过期的。
下面举个例子,使用node搭建服务器来详细说明 jwt 的具体用法。
1.用户通过提供身份信息(如账号和密码)进行身份验证
2.服务器验证用户提供的身份信息,如果验证通过,则并生成一个token并返回给客户端
jsx
if (req.query["username"] && req.query["password"]) {
const { password, username } = req.query;
// 1. 根据用户名查找用户
const user = await Admin.findOne({ username }).select("+password");
// 如果用户名没找到
if (!user) return resp.send({ code: 422, message: "用户不存在!" });
// 2. 校验密码(比较明文和密文的密码)
const isTrue = require("bcryptjs").compareSync(password, user.password);
// 如果密码错误,则抛出错误状态码和错误信息
if (!isTrue) return resp.send({ code: 422, message: "密码错误!" });
// 3. 返回token值(利用公钥加密用户的唯一id,得到token值,并且设置了过期时间为2小时)
const token = jwt.sign({ id: user._id }, app.SECRET, { expiresIn: "2h" });
// 查找用户信息
const userInfo = await Admin.find({ username: req.query.username }).sort({
timeStamp: -1,
});
// 成功生成 JWT,将 JWT 返回给客户端
resp.setHeader("Access-Control-Allow-Origin", "*");
resp.setHeader("Access-Control-Expose-Headers", "Authorization");
resp.setHeader("Authorization", `Bearer ${token}`);
return resp.send({ token, code: 200, userInfo });
}
3.客户端将 token 保存到本地中
jsx
//设置响应拦截器
instance.interceptors.response.use(
(res) => {
if (res.headers.authorization) {
const token = res.headers.authorization.split(" ")[1]
console.log('token',token);
localStorage.setItem('token',token)
}
// 拦截后需要将拦截下来处理成的结果返回
return res.data;
},
(err) => {
console.log(err);
}
);
4.在后续请求中将 token 放在请求的头部,以表示用户的身份
jsx
// 请求拦截器
instance.interceptors.request.use(
(config) => {
// 将token拿出来,拼接到请求头上
const token = localStorage.getItem("token");
if (token) {
config.headers.Authorization = `Bearer ${jwt}`;
}
//请求成功的函数
return config;
},
(err) => {
return err;
}
);
5.服务器在接收到请求时,验证 token 的有效性,并根据其中的信息进行授权和验证。
jsx
// 判断用户token是否合法
router.get("/verify", async (req, resp) => {
const { token } = req.query;
console.log(token);
**// 如果token是伪造的,则直接抛出异常
try {
const obj = jwt.verify(token, app.SECRET);
console.log(obj);
// obj.exp 是过期的时间(单位为s)
if (Date.now() >= obj.exp * 1000) {
resp.send({ code: 401, message: "无效的JWT令牌" });
} else {
resp.send({ code: 200, message: "success" });
}
} catch (error) {
resp.send({ code: 401, message: "无效的JWT令牌" });
}
});