0.前言
在企业级开发中,Token 认证机制已成为保护 API 安全的行业标准。
本文将演示如何通过 Node.js 生成 JSON Web Token (JWT),并结合 Redis 缓存实现完整的认证流程。
1.安装工具库
- express:Express 的作用相当于 node.js 的内置模块 http,是专门用来创建web服务器的。用来接收前端的请求。
- jsonwebtoken:生成、校验 token 的工具。
- ioredis:缓存数据的工具,对 redis 插件进行封装,集成 promise 等工具。
- dotenv:用来管理本地环境变量。
- mysql2:操作数据库
- sequelize:封装数据库操作,通过内置 api 而不是sql语句操作数据库。
css
npm install express jsonwebtoken ioredis dotenv mysql2 sequelize
2.配置环境
在项目根目录新建 .env 文件
在 app.js 中配置 dotenv
css
require('dotenv').config();
然后我们就可以在项目中自定义的文件中获取 .env 文件中配置的数据了,例如:
css
process.env.REDIS_PORT
3.配置 redis
Redis 是一个高性能的键值存储数据库,常用于缓存、消息队列、会话存储等场景。
在 Node.js 中使用 Redis 可以显著提升应用性能,尤其是在频繁读取数据的场景下。
如果你是前端小白,这里你就把 Redis 当成一个很牛逼的数据库,可以存各式各样的数据,可以给存储的数据设置过期时间,时间一到就自动删除了。
Redis 和 MySQL 数据库一样,分为服务端和客户端。服务端用来存储数据,客户端用来对数据进行读写操作。
所以我们要先安装服务端,再安装客户端。
安装 Redis 服务端的文章大家可以自行搜索,或者去问 DeepSeek、豆包等大模型,这里不再赘述。
而本文我们安装的 ioredis 是一个 Node.js 环境下的 Redis 客户端库。我们可以通过它内置的 API 操作 Redis 数据库中的数据。
3.1 配置 Redis
新建 config 文件夹,然后新建 redis.js 文件:
将创建好的 Redis 配置文件加载到 app.js 中
4.jwt 生成 token
古代调兵遣将需要兵符,这个兵符就是个凭证,凭证为真,兵部才允许你把兵调走。
同样在系统开发中,只有是这个系统的用户才被允许访问一些资源。
1.前端用户登陆成功之后,后台通过一个工具将一段字符串返回给前端用户。
2.前端用户每次访问其他页面(资源)的时候请求头都携带这个字符串。
3.后端拿到这个字符串之后再用工具去校验,校验通过,就允许访问其他资源。
所以我们说的字符串就是 token,只不过这个字符串比较复杂。
而JWT是一种具体的 Token 实现方式,是一种认证解决方案。
你可以把 token 看做是 JWT。
而项目中我们安装的 jsonwebtoken 是一个生成 token 字符串、校验 token 的工具。比如它的生成 token 的方法:
css
jwt.sign(
user,// Payload
JWT_SECRET, // 秘钥
{ expiresIn: "1h" } // 令牌过期时间(1小时)
);
所以 JWT 由三部分组成,用点号(.)分隔:
- Header(头部):包含令牌的类型和签名算法。
- Payload(载荷):包含声明(Claims),即关于用户或其他实体的信息。
- Signature(签名):用于验证令牌的完整性和真实性。 一个典型的 JWT 看起来像这样:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaGFuIEdvZGxleSIsImlhdCI6MTUxNjIzOTAzMCwiZXhwIjoxNTE2MjM5MDkwfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
也就是使用 jsonwebtoken 库的 sign 方法就能生成一个 token 字符串。
前面说了一堆废话,接下来配置 jwt 工具:在 utils 文件夹在新建 jwt.js 文件
在 app.js 文件中加载 jwt
注:jsonwebtoken 设置 token 过期时间有两种方式:
1.数值,1小时是60x60x1000=3600000
css
const token = jwt.sign(
{ id: user.id, },// Payload
process.env.JWT_SECRET, // 秘钥
{ expiresIn: 3600000 }
);
2.字符串: 1h表示1小时,2m表示2分钟,24d表示24天
css
const token = jwt.sign(
{ id: user.id, },// Payload
process.env.JWT_SECRET, // 秘钥
{ expiresIn: "1h" }
);
5.改造用户登陆接口
核心流程:
- 1.获取请求参数:username 和 password
- 2.使用 sequelize 的 findOne 方法查询用户信息。注:sequelize 工具的使用在前面几篇文章讲的有,这里不再赘述。
- 3.如果用户不存在,返回错误信息。
- 4.用户存在,密码不对,返回错误信息
- 5.生成 token 信息
- 6.将token信息存储到 redis,设置过期时间
- 7.将token返回给前端
css
// 用户登陆
router.post('/login', async (req, res) => {
try {
const { username, password } = req.body;
// 根据用户名查询用户信息
const user = await User.findOne({
where: {
username: username,
}
});
// 用户存在
if (user) {
// 校验密码
if (password != user.password) {
throw new CustomError("密码错误!");
}
// 生成token
const token = generateToken(user);
// 将token存储到Redis
await redisClient.set(`token:${user.id}`, token, 'EX', 3600); // 1小时过期
// 将token返回
const result = { token: token };
success(res, "登录成功", result);
} else {
throw new CustomError("用户不存在!");
}
} catch (err) {
res.status(500).json({ error: err.message });
}
});
注:redis 存储数据的方法:
- 参数1:key
- 参数2:value
- 参数3:固定,表示设置过期时间
- 参数4:过期时间具体值,3600表示 1 小时,和jwt不一样
vbnet
redisClient.set(key, value, 'EX', 过期时间)
测试结果:
密码错误
登陆成功,返回 token 信息
6.Token 身份校验
在 utils 文件夹下新建 auth.js 文件:
核心流程:
- 1.从请求头中获取 token 信息,如果 token 不存在,就返回错误信息
- 2.使用 jsonwebtoken 库的 verify 方法校验 token 信息,校验失败返回错误信息
- 3.从Redis缓存中获取 token 信息,如果 token 不存在,就返回错误信息
- 4.校验成功,才能访问其他资源
然后在需要进行安全校验的接口上面添加这个方法:
测试:
1.header 为空
2.token校验失败
3.token校验成功
7.完整代码
css
通过网盘分享的文件:zhifou-mall-node-api.zip
链接: https://pan.baidu.com/s/10zOgKQiNfBIrppfAUk6lpw?pwd=6666
提取码: 6666
拿到代码之后记得:
- npm install 安装依赖
- 修改 Sequelize.js 里面连接 MySQL 数据库的账号密码等配置项
- 修改 .env 文件 redis 的配置信息
- npm app.js 启动后端项目