如何在JWT过期后自动发送并验证Refresh Token(Handlebars环境)
自动刷新JWT实现持久登录(Handlebars + Express)
问题现状
登录后生成的JWT有效期仅30秒,过期后刷新页面会被强制退出;已实现Refresh Token接口,但无法自动触发更新JWT Cookie,需要无手动操作的自动续期方案。
解决方案步骤
1. 修复后端Refresh Token接口Bug
当前refreshToken控制器存在多处错误,先修正:
- 捕获JWT过期/无效的抛出异常
- 修正
req.cookie的拼写错误(应为req.cookies) - 移除无用的
next()调用,改为返回明确响应 - 优化Cookie清理逻辑
修正后的refreshToken控制器代码:
exports.refreshToken = async (req, res) => { const token = req.cookies.jwt; if (!token) { return res.status(401).send({ message: "未找到有效token" }); } try { // 验证当前token(未完全过期即可通过) const user = jwt.verify(token, "helloworld"); // 清理旧JWT Cookie res.clearCookie('jwt', { path: '/' }); // 生成新JWT const newToken = jwt.sign({ _id: user._id.toString() }, 'helloworld', { expiresIn: "30s" }); // 设置新JWT Cookie res.cookie("jwt", newToken, { path: '/', expires: new Date(Date.now() + 1000 * 30), httpOnly: true, sameSite: "lax" }); return res.status(200).send({ message: "token已刷新" }); } catch (err) { // 处理token过期/无效情况 res.clearCookie('jwt', { path: '/' }); return res.status(401).send({ message: "登录已过期,请重新登录" }); } }
同时修复verifyToken中间件的异常处理:
exports.verifyToken = async (req, res, next) => { const token = req.cookies.jwt; if (!token) { return res.status(401).send({ message: '未登录,请先登录' }); } try { const user = jwt.verify(token, "helloworld"); req.id = user._id; next(); } catch (err) { res.clearCookie('jwt', { path: '/' }); return res.status(401).send({ message: '登录已过期,请重新登录' }); } }
2. 配置Refresh Token路由
在路由文件中添加有效路由:
// 该接口无需verifyToken验证,用于刷新即将过期的token router.get('/refresh-token', refreshToken);
3. 前端Handlebars页面添加自动刷新逻辑
在user.hbs页面底部添加脚本,定时调用刷新接口(提前5秒触发,避免token过期后请求失败):
<script> // 每25秒触发一次token刷新 setInterval(async () => { try { const response = await fetch('/refresh-token', { method: 'GET', credentials: 'include' // 必须携带Cookie,后端才能读取JWT }); if (response.status === 401) { // token完全过期,跳转登录页 window.location.href = '/login'; } } catch (err) { console.error('刷新token失败:', err); } }, 25000); </script>
4. 优化登录接口Cookie设置(可选)
若需调整初始token有效期,修改login控制器中的Cookie过期时间:
res.cookie("jwt", token, { path: '/', expires: new Date(Date.now() + 1000 * 30), // 保持30秒有效期 httpOnly: true, sameSite: "lax" });
关键注意事项
- HttpOnly Cookie:由于JWT是HttpOnly属性,前端无法直接读取过期时间,固定间隔提前刷新是最稳妥的方案
- 错误处理:若刷新请求返回401,说明token已完全过期,直接跳转登录页
- 凭证携带:前端请求必须携带
credentials: 'include',否则后端无法读取Cookie中的JWT
内容的提问来源于stack exchange,提问作者mahir
相关产品推荐
相关产品推荐

