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

Node.js Discord授权WebSocket Bot连接被拒:已获取有效Token但仍报“Missing token!”

Node.js Discord授权WebSocket Bot连接被拒:已获取有效Token但仍报“Missing token!”

从你的描述和日志来看,问题核心是:用户通过Discord OAuth2成功登录并获取了有效Token,但WebSocket连接始终因为会话未被识别而被拒绝(日志中Odrzucono połączenie WebSocket - użytkownik niezalogowany!翻译为“WebSocket连接被拒绝 - 用户未登录”)。以下是问题分析和分步修复方案:

问题根源诊断

  1. 会话Cookie未在WebSocket握手时发送:浏览器默认可能不会自动在WebSocket请求中携带HttpOnly Cookie,或Cookie配置存在问题。
  2. 内存会话存储不稳定:当前用SESSIONS对象存储会话,服务器重启后所有会话会丢失,即使用户持有有效Cookie。
  3. Cookie解析逻辑鲁棒性不足:手动拆分Cookie的方式可能无法处理复杂的Cookie字符串格式。
  4. WebSocket服务器实例缺失:你提供的代码中缺少WebSocket服务器的初始化代码(可能是粘贴遗漏,但会导致server.handleUpgrade报错)。
  5. Cookie属性不完整:未设置SameSite等属性,可能导致浏览器在某些上下文下拒绝发送Cookie。

分步修复方案

1. 补全WebSocket服务器初始化

在引入ws模块后,添加WebSocket服务器实例:

const WebSocket = require("ws");
const server = new WebSocket.Server({ noServer: true }); // 新增:创建无服务器绑定的WebSocket实例

2. 优化会话Cookie配置

在handleAuthCallback中设置Cookie时,添加安全属性,确保Cookie能被WebSocket请求携带:

res.writeHead(302, {
    "Set-Cookie": `session=${sessionId}; Path=/; HttpOnly; SameSite=Strict; ${process.env.NODE_ENV === 'production' ? 'Secure' : ''}`,
    "Location": "/"
});
  • SameSite=Strict:确保Cookie仅在同域请求中发送
  • Secure:生产环境下仅通过HTTPS发送Cookie(需启用HTTPS)
  • HttpOnly:防止XSS攻击,不影响WebSocket请求携带Cookie

3. 替换为express-session处理会话(更可靠)

手动会话管理容易出错,改用express-session来处理会话解析和存储:

// 初始化会话中间件
const sessionMiddleware = session({
    secret: process.env.SESSION_SECRET || "your-strong-secret-key-here", // 生产环境用环境变量存储密钥
    resave: false,
    saveUninitialized: false,
    cookie: {
        httpOnly: true,
        sameSite: "Strict",
        secure: process.env.NODE_ENV === "production",
        maxAge: 7 * 24 * 60 * 60 * 1000 // 与Discord Token有效期一致(7天)
    }
});

// 在Express中使用会话中间件
app.use(sessionMiddleware);

然后修改handleAuthCallback,将用户ID存入express-session:

async function handleAuthCallback(req, res) {
    // ... 原有代码省略 ...
    console.log("User data:", userData);
    
    // 将用户ID存入会话
    req.session.userId = userData.id;
    await new Promise((resolve, reject) => {
        req.session.save((err) => err ? reject(err) : resolve());
    });
    
    res.writeHead(302, { Location: "/" });
    res.end();
}

4. 在WebSocket升级处理中使用会话中间件

由于WebSocket升级请求不经过Express路由,需手动调用会话中间件解析Cookie:

httpServer.on("upgrade", (request, socket, head) => {
    // 先通过会话中间件解析请求中的会话
    sessionMiddleware(request, {}, () => {
        const pathname = url.parse(request.url).pathname?.replace(/\/$/, "");
        
        if (pathname === "/server") {
            const userId = request.session.userId;

            if (!userId) {
                console.log("❌ Odrzucono połączenie WebSocket - użytkownik niezalogowany!");
                return socket.destroy();
            }

            console.log(`✅ Połączony użytkownik Discord ID: ${userId}`);
            server.handleUpgrade(request, socket, head, (ws) => {
                server.emit("connection", ws, request);
            });
        } else {
            socket.destroy();
        }
    });
});

5. 确保前端WebSocket请求携带凭证

如果前端是浏览器,创建WebSocket连接时显式指定携带凭证(同域下默认会携带,但显式设置更可靠):

// 前端JavaScript代码
const ws = new WebSocket("ws://localhost:PORT/server", {
    credentials: "include"
});

6. 生产环境改用持久化会话存储

内存会话在服务器重启后会丢失,推荐使用Redis或MongoDB等持久化存储:

// 示例:使用Redis存储会话
const RedisStore = require("connect-redis")(session);
const redis = require("redis");
const redisClient = redis.createClient({ url: process.env.REDIS_URL });
redisClient.connect().catch(console.error);

const sessionMiddleware = session({
    store: new RedisStore({ client: redisClient }),
    secret: process.env.SESSION_SECRET,
    resave: false,
    saveUninitialized: false,
    // 其他Cookie配置...
});

验证修复效果

  1. 重启服务器,重新通过Discord登录
  2. 打开浏览器DevTools > 应用 > Cookie,确认session Cookie已设置
  3. 发起WebSocket连接,在网络面板中查看握手请求的Cookie头是否包含session字段
  4. 检查服务器日志,确认是否输出✅ Połączony użytkownik Discord ID: [用户ID]

备注:内容来源于stack exchange,提问作者Wojtek Szymański

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 09:48:09