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

Passport Discord OAuth2适配MySQL替代MongoDB的schema实现方案咨询

实现方案

首先澄清核心误解:passport 没有强制要求 done 函数传入的 user 必须是 mongoose schema 实例,只要是包含业务所需字段的普通 JS 对象即可,完全可以搭配 MySQL 使用。

1. 首先创建MySQL用户表

你可以先建一张存储Discord授权用户信息的表,参考建表SQL:

CREATE TABLE `discord_users` (
  `id` int UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `discord_id` varchar(32) NOT NULL UNIQUE COMMENT 'Discord用户唯一ID',
  `username` varchar(100) NOT NULL,
  `email` varchar(100) DEFAULT NULL,
  `avatar` varchar(255) DEFAULT NULL,
  `access_token` varchar(255) NOT NULL,
  `refresh_token` varchar(255) NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

2. 修改DiscordStrategy回调逻辑

你可以用mysql2或者Sequelize这类MySQL客户端/ORM来操作数据库,替换原有mongoose的逻辑,示例如下(以mysql2/promise为例):

const mysql = require('mysql2/promise');
// 初始化MySQL连接池
const pool = mysql.createPool({
  host: process.env.MYSQL_HOST,
  user: process.env.MYSQL_USER,
  password: process.env.MYSQL_PASSWORD,
  database: process.env.MYSQL_DB,
  waitForConnections: true,
  connectionLimit: 10,
  queueLimit: 0
});

passport.use(new DiscordStrategy({
    clientID: process.env.CLIENT_ID,
    clientSecret: process.env.CLIENT_SECRET,
    callbackURL: process.env.CLIENT_REDIRECT,
    scope: ['identify', 'email', 'guilds']
}, async (accessToken, refreshToken, profile, done) => {
    try {
        // 先查找用户是否已经存在
        const [rows] = await pool.query('SELECT * FROM discord_users WHERE discord_id = ?', [profile.id]);
        let user;
        if (rows.length > 0) {
            // 用户存在,更新token
            await pool.query(
                'UPDATE discord_users SET access_token = ?, refresh_token = ?, username = ?, email = ?, avatar = ? WHERE discord_id = ?',
                [accessToken, refreshToken, profile.username, profile.email, profile.avatar, profile.id]
            );
            user = rows[0];
        } else {
            // 用户不存在,新建记录
            const [result] = await pool.query(
                'INSERT INTO discord_users (discord_id, username, email, avatar, access_token, refresh_token) VALUES (?, ?, ?, ?, ?, ?)',
                [profile.id, profile.username, profile.email, profile.avatar, accessToken, refreshToken]
            );
            user = {
                id: result.insertId,
                discord_id: profile.id,
                username: profile.username,
                email: profile.email,
                avatar: profile.avatar,
                accessToken,
                refreshToken
            };
        }
        // 直接传普通用户对象即可,不需要mongoose实例
        done(null, user);
    } catch (err) {
        done(err, null);
    }
}))

3. 配套修改passport序列化与反序列化逻辑

这一步是保证session读写正常的关键,需要对应MySQL的用户字段修改:

// 序列化:把用户ID存到session
passport.serializeUser((user, done) => {
  done(null, user.id);
});

// 反序列化:从session拿ID到MySQL查用户完整信息
passport.deserializeUser(async (id, done) => {
  try {
    const [rows] = await pool.query('SELECT * FROM discord_users WHERE id = ?', [id]);
    if (rows.length === 0) return done(null, false);
    done(null, rows[0]);
  } catch (err) {
    done(err, null);
  }
});

可选:用Sequelize ORM定义类schema模型

如果你习惯了mongoose的schema写法,可以用Sequelize来定义MySQL的用户模型,功能和mongoose schema对等,示例如下:

const { Sequelize, DataTypes } = require('sequelize');
const sequelize = new Sequelize(process.env.MYSQL_DB, process.env.MYSQL_USER, process.env.MYSQL_PASSWORD, {
  host: process.env.MYSQL_HOST,
  dialect: 'mysql'
});

const DiscordUser = sequelize.define('DiscordUser', {
  discord_id: {
    type: DataTypes.STRING(32),
    allowNull: false,
    unique: true
  },
  username: {
    type: DataTypes.STRING(100),
    allowNull: false
  },
  email: DataTypes.STRING(100),
  avatar: DataTypes.STRING(255),
  access_token: DataTypes.STRING(255),
  refresh_token: DataTypes.STRING(255)
}, {
  tableName: 'discord_users',
  timestamps: true,
  createdAt: 'created_at',
  updatedAt: 'updated_at'
});

// 同步模型到数据库(首次运行执行一次即可)
// DiscordUser.sync({ alter: true });

后续操作直接调用Sequelize提供的findOne、create、update方法即可,写法和mongoose高度相似。

不需要把mongoose schema存储到MySQL,直接按上述方案迁移为MySQL的表结构/Sequelize模型即可,整个流程完全不需要依赖MongoDB。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 10:18:03