JWT
json web token。实现身份验证或授权,也就是鉴权。(常用于用户登录后需要存储用户信息)
有点类似 cookie 和 session。
原理
在服务端生成一个加密的令牌(token),将用户的信息封装到这个令牌中;前端每一次发送请求时去携带这个 token,服务端就可以将这个 token 进行解码,读取用户的信息,这样就达到了一个身份验证和鉴权。
组成
JWT 由 . 分割为三个部分:
- 头部(Header):一般由令牌的类型和使用的签名算法组成(一般不用去管),是一个 json 对象。
- 负载(Payload):包含需要传输的信息(用户身份、权限、令牌发布者等),也是一个 json 对象,使用 Base64 进行编码。
- 验证签名(Verify Signature):通过指定算法对 Header 和 Payload 生成数字签名。
实现
后端(express)
- 安装所需依赖
pnpm i express cors jsonwebtoken
cors:用于解决跨域。
import express from "express";
import jwt from "jsonwebtoken";
import cors from "cors";
let Key = "SVCSD"; // 加验私钥,一般藏在环境变量里
const app = express();
app.use(express.json()); // 中间件支持json
app.use(express.urlencoded({ extended: false }));
app.use(cors()); // 中间件解决跨域
let user = {
name: "admin",
password: "123456",
id: 1,
};
// 1.登录返回前端token用于授权
app.post("/api/login", (req, res) => {
if (req.body.name == user.name && req.body.password == user.password) {
res.json({
message: "登录成功",
token: jwt.sign({ id: user.id }, Key, { expiresIn: "1h" }), // payload,私钥,token配置对象(如 token 过期时间)
});
} else {
res.status(403).json({ message: "用户名或密码错误" });
}
});
// 2.列表接口,只有授权状态才能访问,不然就会403
app.post("/api/list", (req, res) => {
let token = req.headers.authorization; // 前端 token 存放在请求头的 authorization 里,规范
jwt.verify(token, Key, (err, decode) => {
// 使用 jwt 去验证 token 是否正确
if (err) {
// token 没有权限按规范返回403
res.status(403).json({ message: "无权限" });
} else {
res.json({
list: [
{ id: 1, title: "标题1" },
{ id: 2, title: "标题2" },
],
});
}
});
});
app.listen(3000, () => {
console.log("server started");
});
前端(fetch)
btn.onclick = () => {
fetch("http://localhost:3000/api/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
name: name.value,
password: password.value,
}),
})
.then((res) => res.json())
.then((res) => {
cnosole.log(res);
localStorage.setItem("token", res.token);
});
};
fetch("http://localhost:3000/api/list", {
headers: {
Authorization: localStorage.getItem("token"),
// "Authorization": `Bearer ${localStorage.getItem("token")}`
},
})
.then((res) => res.json())
.then((res) => {
cnosole.log(res);
});
注意:Bearer 字段不是一定要加的,它是一个规范,只要看见 token 前面加了这个东西,就说明它使用了 OAuth 2.0 规范(jwt 也使用了该规范)。加了后端也需要去处理这个 Bearer