如何修改Node.js登录代码实现多设备同时登录
实现Node.js多设备同时登录不互踢的修改方案
当前代码在用户新设备登录时,会通过User.updateOne覆盖用户表中的auth_token字段,导致旧设备的token失效。要实现多设备同时登录,需要调整token的存储和验证逻辑,具体修改如下:
核心问题分析
原代码的问题在于:
- 登录时将新token写入User表的
auth_token字段,直接覆盖旧token,导致旧设备无法通过身份验证 - 仅依赖User表的单个token做身份校验,天然不支持多设备并存
修改步骤
1. 删除User表更新auth_token的代码
登录过程中不再更新User表的auth_token字段,每个设备的token独立存储在LoginInfo表中即可。
找到并删除这段代码:
await User.updateOne({_id:user_data._id}, { $set:{ auth_token:token } })
2. 重构token验证逻辑(关键)
原验证逻辑应该是对比请求token与User表的auth_token,现在需要改为从LoginInfo表中校验token有效性:
- 解析JWT获取用户ID(
sub字段) - 在
LoginInfo表中查询该用户对应的、未过期且未被注销的token记录 - 存在匹配记录则验证通过
示例验证中间件代码:
async function authenticateToken(req, res, next) { const authHeader = req.headers['authorization']; const token = authHeader && authHeader.split(' ')[1]; if (!token) return res.sendStatus(401); try { // 这里要和登录时用的密钥一致 const jwtkey = req.user?.user_id?.split("/")[0] || /* 从用户信息获取密钥的逻辑 */; const payload = jwt.verify(token, jwtkey); // 校验token是否在LoginInfo中有效 const validLogin = await LoginInfo.findOne({ user_id: payload.sub, auth_token: token, // 可选:和JWT过期时间同步,自动清理过期token expires_at: { $gt: new Date() } }); if (!validLogin) return res.sendStatus(401); req.user = payload; next(); } catch (err) { return res.sendStatus(403); } }
3. 可选:给LoginInfo添加过期时间字段
为了自动管理过期token,创建LoginInfo时可以添加expires_at字段,和JWT的过期时间保持一致:
// 修改登录时创建LoginInfo的代码 await LoginInfo.create({ user_id: user_data.user_id, sys_info: sys_info ? sys_info.split('"').join("") : "NA", browser_info: browser_info ? browser_info.split('"').join(" ") : "NA", ip_address: ipaddr, timestamp: time, access_token: access_token, auth_token: token, expires_at: new Date(Date.now() + 24 * 60 * 60 * 1000) // 24小时后过期 });
4. 可选:支持用户手动注销设备
添加接口让用户主动注销某台设备的token:
async function logoutDevice(req, res) { const { token } = req.body; // 或者让用户选择设备ID来注销 await LoginInfo.deleteOne({ auth_token: token }); res.json({ status: 200, message: "设备已成功注销" }); }
内容的提问来源于stack exchange,提问作者Shivanshu Singh
相关产品推荐
相关产品推荐

