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

Discord OAuth白名单系统故障求助:Node.js角色验证逻辑修复

Discord白名单验证系统修复方案

核心问题梳理

  • OAuth授权类型不匹配:登录链接使用response_type=token,但后端采用授权码模式,需改为response_type=code
  • 令牌使用错误:调用服务器列表接口时误用授权码(code)作为身份凭证,应使用获取到的accessToken
  • 权限不足:仅identify权限无法获取用户角色,需新增guilds.members.read权限
  • 接口数据误用:/users/@me/guilds不返回用户角色,需调用服务器成员接口单独查询
  • 逻辑分支缺失:未处理用户不在目标服务器的场景,也未按要求返回指定状态文本

修复后的完整代码

const express = require('express');
const axios = require('axios');

const app = express();
const PORT = 3000;

const CLIENT_ID = '1332081657993367582'; 
const REQUIRED_ROLE_ID = "1325501603201028171";
const GUILD_ID = "1325501050471448647";
const CLIENT_SECRET = process.env.CLIENT_SECRET; 
const REDIRECT_URI = `https://dour-repeated-gasoline.glitch.me/validate`; 
const SCOPE = 'identify guilds.members.read'; 

app.get('/login', (req, res) => {
    const discordOAuthURL = 
        `https://discord.com/oauth2/authorize?` +
        `client_id=${CLIENT_ID}` +
        `&response_type=code` +
        `&redirect_uri=${encodeURIComponent(REDIRECT_URI)}` +
        `&scope=${encodeURIComponent(SCOPE)}`;
    res.redirect(discordOAuthURL);
});

app.get('/validate', async (req, res) => {
    const { code } = req.query;

    if (!code) {
        return res.status(400).send('ERROR');
    }

    try {
        // 获取访问令牌
        const tokenResponse = await axios.post('https://discord.com/api/oauth2/token', null, {
            params: {
                client_id: CLIENT_ID,
                client_secret: CLIENT_SECRET,
                grant_type: 'authorization_code',
                code,
                redirect_uri: REDIRECT_URI,
            },
            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        });

        const accessToken = tokenResponse.data.access_token;
        const userId = tokenResponse.data.user_id;

        // 查询用户在指定服务器的成员信息
        try {
            const memberResponse = await axios.get(`https://discord.com/api/v10/guilds/${GUILD_ID}/members/${userId}`, {
                headers: { Authorization: `Bearer ${accessToken}` },
            });

            // 检查是否拥有指定角色
            const hasRequiredRole = memberResponse.data.roles.includes(REQUIRED_ROLE_ID);
            res.send(hasRequiredRole ? "ACCEPTED" : "DECLINED");
        } catch (memberError) {
            // 404表示用户不在该服务器
            if (memberError.response?.status === 404) {
                res.send("NONMEMBER");
            } else {
                throw memberError;
            }
        }
    } catch (error) {
        console.error('Error during validation:', error.response?.data || error.message);
        res.status(500).send('ERROR');
    }
});

app.listen(PORT, () => {
    console.log(`Server is running on http://localhost:${PORT}`);
});

关键修改说明

  1. OAuth流程修正:将登录链接的response_type改为code,匹配后端授权码模式
  2. 权限补充:新增guilds.members.read权限,允许查询用户在服务器的角色信息
  3. 令牌修正:调用接口时使用accessToken而非授权码作为Bearer凭证
  4. 角色查询逻辑:通过/guilds/{GUILD_ID}/members/{userId}接口获取用户在目标服务器的角色列表
  5. 状态返回完善:新增用户不在服务器的NONMEMBER分支,异常统一返回ERROR
  6. 错误处理优化:捕获成员查询的404错误,精准判断用户是否为服务器成员

内容的提问来源于stack exchange,提问作者İlyax

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 18:14:51