session 认证的缺点
Session 认证机制需要配合 Cookie 才能实现。由于 Cookie 默认不支持跨域访问,所以,当涉及到前端跨域请求后端接口的时候,需要做很多额外的配置,才能实现跨域 Session 认证。
注意:
● 当前端请求后端接口不存在跨域问题的时候,推荐使用 Session 身份认证机制。
● 当前端需要跨域请求后端接口的时候,不推荐使用 Session 身份认证机制,推荐使用 JT 认证机制。
JWT 是什么
JWT(英文全称:JSON Web Token)是目前最流行的跨域认证解决方案。
JWT 认证的工作原理
总结:用户信息通过 token 字符串的形式,保存在客户端浏览器中,在需要验证身份的接口中,服务端对请求中的头信息进行分析,还原 token 信息来进行身份认证
JWT 的组成部分
由三部分组成,分别是 Header(头部),Payload(有效载荷),Signature(签名),之间用.分割
其中:
- Payload 部分才是真正的用户信息,"它是用户信息经过加密之后生成的字符串。
- Header 和 Signature 是安全性相关的部分,只是为了保证 Token 的安全性
JWT 使用方式
客户端收到服务器返回的 JT 之后,通常会将它储存在 localStorage 或 sessionStorage 中。此后,客户端每次与服务器通信,都要带上这个 JWT 的字符串,从而进行身份认证。推荐的做法是把 JWT 放在 HTTP 请求头的 Authorization 字段中,格式如下:
Authrizatuion:Bearer <token>
相关依赖
npm i jsonwebtoken express-jwt
● jsonwebtoken 用于生成JWT 字符串
● express-jwt 用于将 JWT 字符串解析还原成 JSON 对象
"dependencies": {
"body-parser": "^1.20.2",
"cors": "^2.8.5",
"ejs": "^3.1.9",
"express": "^4.19.2",
"express-jwt": "^8.4.1",
"jsonwebtoken": "^9.0.2",
"mysql": "^2.18.1"
}
实战代码
入口文件app.js
const express = require("express");
const userRouter = require("./router/user");
const bookRouter = require("./router/book");
const bodyParser = require("body-parser");
const path = require("path");
const cors = require("cors");
const app = express();
const { expressjwt } = require("express-jwt");
const jwtConfig = require("./config/index");
app.use(express.static("public"));
//ejs模版的必须配置
// app.set("view engine", "ejs");
// app.set("views", path.join(__dirname, "views"));
//解析请求体参数
app.use(bodyParser.json());
app.use(express.urlencoded({ extended: false }));
//jwt中间件
//安装的express-jwt模块会默认为最新版本,更新后的jwt需要在配置中加入algorithms属性,即设置jwt的算法。一般HS256为配置algorithms的默认值。
app.use(
expressjwt({ secret: jwtConfig.jwtSecret, algorithms: ["HS256"] }).unless({
path: [/^\/api\//],
})
);
//跨域资源共享
app.use(cors());
app.use("/api", userRouter);
app.use("/book", bookRouter);
//错误级别的中间件
app.use((err, req, res, next) => {
console.log("🚀 ~ app.use ~ err:", err);
//token解析失败
if (err.name === "UnauthorizedError") {
return res.send({
status: 401,
message: "无效的token",
});
}
res.send({
status: 500,
message: "服务端错误",
});
});
app.listen(4444, () => {
console.log("app is running on port 4444");
});
注意:
- 最新版本的express-jwt这里需要结构
const { expressjwt } = require("express-jwt");
- 配置项新增的参数algorithms:默认HS256即可,意思是除了以/api/开始的接口外,其余全部需要携带token发送请求
app.use(
expressjwt({ secret: jwtConfig.jwtSecret, algorithms: ["HS256"] }).unless({
path: [/^\/api\//],
})
);
秘钥
const jwtSecret = "gaofeng.8866";
module.exports = {
jwtSecret,
};
登录模块
const express = require("express");
const router = express.Router();
const jwt = require("jsonwebtoken");
const jwtConfig = require("../config/index");
router.post("/login", (req, res) => {
const { username, password } = req.body;
if (username != "admin" && password != "123456") {
return res.send({
status: 1,
msg: "登录失败",
});
}
//登录成功之后,生成jwt字符串,并通过token的形式返回给客户端
//参数:用户的信息对象,加密的秘钥,配置的对象(当前token的有效期 30s | 2h)
const token = jwt.sign({ username: username }, jwtConfig.jwtSecret, {
expiresIn: "30s",
});
res.send({
status: 0,
msg: "登录成功",
token,
});
});
注意:
- 登录成功之后,生成jwt字符串,并通过token的形式返回给客户端
- 参数:用户的信息对象,加密的秘钥,配置的对象(当前token的有效期 30s | 2h)
测试验证
- 不携带及过期token,都会被全局的错误中间件拦截,并返回定制的错误消息
-
登录
这样就返回了token字符串 -
再次发起预约接口
这样我们就实现了jwt身份鉴权验证
我们在其他接口中解析客户端的token信息的时候,最新版的express-jwt有变化,需要使用req.auth来获取客户端的token,与较早版本的获取方式有差异,req.user,这里需要注意!!!
到这里,关于jwt鉴权我们就算是完成了!!!_