express框架中登录使用redis保存token
(一)
1.电脑安装redis
下载地址
点击下载
提取码 wwhh
2.安装好后,进入到安装目录下启动redis
执行启动:
redis-server.exe redis.windows.conf
(二)Express 项目配置 Redis
- expree项目安装redis依赖
npm install express redis dotenv
2.创建 .env 文件,复制下面的2行到.env文件中
REDIS_HOST=localhostREDIS_PORT=6379
2.1创建 Redis 客户端,建议在应用入口app.js初始化
app.js文件
// app.js// ... 其他 require 语句 ...const redis = require(\'redis\');const config = require(\"./config\");var app = express();var http = require(\"http\");var server = http.createServer(app);// ========== Redis 客户端初始化(从这里开始添加) ==========// 创建 Redis 客户端实例const redisClient = redis.createClient({ url: process.env.REDIS_URL || \'redis://localhost:6379\' // 支持环境变量配置});// 处理连接错误redisClient.on(\'error\', (err) => { console.error(\'Redis连接错误:\', err);});// 异步连接Redis(async () => { try { await redisClient.connect(); console.log(\'Redis连接成功\'); } catch (err) { console.error(\'Redis连接失败:\', err); process.exit(1); // 如果Redis连接失败,退出应用 }})();// 将redisClient挂载到app实例上,方便后续路由使用app.locals.redisClient = redisClient;// ========== Redis 初始化结束 ==========// 错误处理中间件中添加 Redis 关闭逻辑process.on(\'SIGINT\', () => { redisClient.quit().then(() => { console.log(\'Redis连接已关闭\'); process.exit(0); });});server.listen(\"5000\", () => { console.log(\"启动成功\");});
3.实现express登录接口保存token到redis
// 登录接口var db = require(\"../utils/db\");// 导入密码加密const bcrypt = require(\"bcryptjs\");// 导入jwt 包来生成tokenconst jwt = require(\"jsonwebtoken\");// 导入密钥const config = require(\"../config\");exports.login = (req, res) => { // 获取客户端提交到服务器的用户信息 const userinfo = req.body; // console.log(\'前端数据\', userinfo) // 定义sql语句,根据用户名查询用户的信息 const sql = `select * from ev_users where username=?`; // 执行sql语句,根据用户名查询用户的信息 db.query(sql, userinfo.username, async (err, results) => { // 执行sql语句失败 if (err) return res.cc(err); // 执行sql语句成功,但是获取到的数据条件不等于1 if (results.length !== 1) return res.cc(\"登录失败!\"); const compareResult = bcrypt.compareSync( userinfo.password, results[0].password ); if (!compareResult) { return res.cc(\"登录失败!\"); } // 生成jwt的token字符串 // 清空用户信息的密码和头像 const user = { ...results[0], password: \"\", user_pic: \"\" }; console.log(\"YONGHU\", user); // 对用户的信息进行加密,生成token字符串 const tokenStr = jwt.sign(user, config.jwtSecretKey, { expiresIn: \"10h\", // token 有效期为10小时 }); try { // 获取Redis客户端实例 const redisClient = req.app.locals.redisClient; // 将Token存储到Redis await redisClient.setEx( `token:${user.id}`, // 键名格式: token:用户ID 36000, // 过期时间(秒): 10小时 = 3600秒/小时 × 10 tokenStr // 值: JWT令牌字符串 ); const storedToken = await redisClient.get(`token:${user.id}`); console.log(\'[Redis验证] 存储的Token:\', storedToken); console.log(\'[Redis验证] 剩余TTL:\', await redisClient.ttl(`token:${user.id}`)); console.log(`Token已存入Redis (用户ID: ${user.id})`); // 响应客户端保持不变 res.send({ status: 0, message: \"登录成功!\", token: \"Bearer \" + tokenStr, }); } catch (redisError) { console.error(\'Redis存储失败:\', redisError); // Redis错误时仍返回登录成功,但记录错误信息 res.send({ status: 0, message: \"登录成功,但Token缓存失败\", token: \"Bearer \" + tokenStr, }); } });};
- 验证 Redis 存储
前端或者用postman发送登录接口,登录成功后验证redis里面是否存在token
1.前端登录成功
2.验证token 是否在redis
在 Redis 目录下启动 CLI
redis-cli.exe
查询数据
127.0.0.1:6379> KEYS *
此时ID为46的token 保存到了redis中
退出登录后从redis里面删除token
退出登录接口
exports.logout = async (req, res) => { try { // 从请求头获取token (格式: Bearer ) const tokenHeader = req.headers.authorization; if (!tokenHeader || !tokenHeader.startsWith(\'Bearer \')) { return res.cc(\"授权信息无效\", 1); } // 提取实际token值 (去除\"Bearer \"前缀) const token = tokenHeader.split(\' \')[1]; // 验证并解码token let decoded; try { decoded = jwt.verify(token, config.jwtSecretKey); } catch (err) { // Token无效(过期或签名错误) return res.cc(\"授权信息已过期或无效\", 1); } // 获取Redis客户端 const redisClient = req.app.locals.redisClient; // 从Redis删除该用户的token const deleteResult = await redisClient.del(`token:${decoded.id}`); if (deleteResult === 1) { console.log(`用户 ${decoded.id} 退出登录成功,Token已删除`); res.cc(\"退出登录成功\", 0); } else { console.log(`用户 ${decoded.id} 退出登录但Token未找到`); res.cc(\"退出登录成功\", 0); // 即使未找到也返回成功,可能已过期 } } catch (err) { console.error(\"退出登录处理错误:\", err); res.cc(\"服务器内部错误\", 1); }};