Express-Session Cookie更新未持久化,跨接口请求返回401
问题描述
我搭建了ExpressJS API与NextJS UI,生成会话令牌时,令牌已成功保存至MongoDB会话存储,但在其他API接口复用该令牌时,请求返回401未授权状态码。尝试过相关问题的解决方案但无效,当前使用容器化Node 18.13.0及最新Mongo镜像。
相关代码示例
app.js
import express from 'express'; import bodyParser from 'body-parser'; import cors from 'cors'; import session from 'express-session'; import helmet from 'helmet'; import MongoDBStore from 'connect-mongodb-session'; import router from './routes/index.js'; app.use(cors({ origin: [ 'http://localhost:8080', 'http://127.0.0.1:8080', 'http://127.0.0.1:3000', 'http://localhost:3000', ], methods: ['POST', 'PUT', 'GET', 'DELETE'], credentials: true, })); app.use(session({ secret: env.SESSION_SECRET, cookie: { maxAge: 3600000, // 1小时 httpOnly: true, rolling: true, secure: false, }, store, resave: false, saveUninitialized: false, })); app.use(router);
./routes/index.js
import Auth from './auth.js'; import crud from './crud.js'; const router = Router(); router.post('/signup', Auth.signup); router.post('/login', Auth.login); router.get('/data', Auth.authMiddleware(['admin', 'basic', 'premium', 'standard']), crud.getData); export default router;
./routes/auth.js
const authMiddleware = (permittedRoles) => async (req, res, next) => { try { if (permittedRoles.indexOf(req.session.user.role) > -1) { next(); } else { await req.session.destroy(); await res.clearCookie('connect.sid'); res.status(401).json('无访问权限'); } } catch (err) { await req.session.destroy(); await res.clearCookie('connect.sid'); await res.status(401).json('会话已过期,请重新登录'); } }; const login = async (req, res) => { try { const maybeUser = await UserController.getUser(req.body.email); if (maybeUser && await bcrypt.compare(req.body.password, maybeUser.password)) { req.session.user = { email: maybeUser.email, role: maybeUser.role }; req.session.save(); // 控制台打印显示.user属性包含email和role res.status(201).json({ success: `欢迎,${req.body.email}`}); } else { res.status(400).json('邮箱或密码错误'); } } catch (err) { res.status(500).json('服务器内部错误,请联系管理员'); } }; const signup = async (req, res) => { try { const { email } = req.body; const password = await bcrypt.hash(req.body.password, 15).then((hash) => hash); const resp = await UserController.addUser({ email, password }); if (resp.success && !resp.error) { res.status(201).json({ success: '用户创建成功' }); } else { res.status(400).json('无法创建账户'); } } catch (err) { res.status(500).json('服务器内部错误,请联系管理员'); } };
./routes/crud.js
const getData = (req, res) => { console.log(req.session); // 会话应包含email和role属性,但实际没有 // ... }
NextJS UI中的API调用
const response = await fetch('localhost:8080/signup', { method: 'POST', body: await statesToFormData(), }); // ... const response = await fetch('localhost:8080/login', { method: 'POST', body: await statesToFormData(), }); const response = await fetch('localhost:8080/data', { method: 'GET', credentials: 'include', });
问题解决
发现req.session.save()需要传入回调函数,修改后的login端点如下:
const login = async (req, res) => { // ... if (...) { req.session.user = { email: maybeUser.email, role: maybeUser.role }; req.session.save((err) => { if (err) { res.status(500).json('保存会话失败,请稍后重试'); } else { res.status(201).json({ success: `欢迎,${req.body.email}`}); } }); } else { // ... } // ... };
内容的提问来源于stack exchange,提问作者XXX
相关产品推荐
相关产品推荐

