You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 01:19:52