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

Next.js技术问题:如何将卡组关联至当前登录用户

问题:Next-Auth用户无法与MongoDB中保存的卡组关联

目标

开发网站功能:登录用户在「Deck editor」页面用数据库卡牌创建卡组,保存时关联个人账户,方便后续登录调取。

当前问题

卡组能保存至数据库,但无法关联当前用户。最初数据库无by关联字段,重启项目后字段出现,但关联逻辑仍不生效。

已完成功能

  • Deck editor仅登录用户可访问
  • 卡牌搜索功能正常
  • 点击搜索结果添加卡牌至卡组,点击已添加卡牌可移除
  • 支持切换「Main」「Side」两种卡组类型

技术栈

Next.js、MongoDB(mongoose连接)、Material UI、Next-Auth

核心代码片段

deckEditing.jsx(前端保存逻辑)

import { useSession } from "next-auth/react";

const DeckEditor = () => {
  const { data: session } = useSession();
  const saveDeck = async () => {
    const deckData = {
      name: deckName,
      main: mainDeck,
      side: sideDeck,
      by: session?.user?.id // 尝试传入用户ID
    };
    await fetch("/api/saveDeck", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(deckData)
    });
  };
};

saveDeck.js(API路由)

import Deck from "../../models/deck";
import { connectDB } from "../../utils/db";
import { getServerSession } from "next-auth/next";
import { authOptions } from "./auth/[...nextauth]";

export default async function handler(req, res) {
  if (req.method !== "POST") return res.status(405).end();
  
  await connectDB();
  const session = await getServerSession(req, res, authOptions);
  if (!session) return res.status(401).json({ message: "未授权" });

  const { name, main, side } = req.body;
  const newDeck = new Deck({
    name,
    main,
    side,
    by: session.user.id // 关联用户ID
  });

  try {
    await newDeck.save();
    res.status(201).json({ message: "卡组保存成功" });
  } catch (err) {
    res.status(500).json({ message: "保存失败", error: err.message });
  }
}

deck.js(Mongoose卡组模型)

import mongoose from "mongoose";

const deckSchema = new mongoose.Schema({
  name: { type: String, required: true },
  main: { type: Array, required: true },
  side: { type: Array, required: true },
  by: { type: mongoose.Schema.Types.ObjectId, ref: "User", required: true } // 关联User模型
});

export default mongoose.models.Deck || mongoose.model("Deck", deckSchema);

user.js(Mongoose用户模型)

import mongoose from "mongoose";

const userSchema = new mongoose.Schema({
  id: { type: String, required: true },
  name: { type: String },
  email: { type: String, required: true, unique: true }
});

export default mongoose.models.User || mongoose.model("User", userSchema);

排查修复步骤

  1. 确认Session中用户ID的正确性

    • 在前端打印session?.user,检查是否存在id字段:
      console.log(session?.user);
      
    • 若使用OAuth登录(如Google),Next-Auth默认用户标识是sub字段,需在[...nextauth].js的回调中映射为id:
      callbacks: {
        async session({ session, user }) {
          session.user.id = user.id || user.sub;
          return session;
        }
      }
      
  2. 强制在API路由获取用户ID(避免前端篡改)

    • 不要依赖前端传入的by字段,必须通过getServerSession在后端获取用户ID,确保安全性。
    • 检查authOptions是否正确导入,getServerSession能否正常返回会话数据。
  3. 验证Mongoose关联字段配置

    • 若User模型使用MongoDB默认的_id(而非自定义id),需调整卡组模型的关联字段:
      // deck.js中修改by字段
      by: { type: mongoose.Schema.Types.ObjectId, ref: "User", required: true }
      // 同时在Next-Auth的session回调中返回用户的_id字符串:
      callbacks: {
        async session({ session, user }) {
          session.user.id = user._id.toString();
          return session;
        }
      }
      
    • 确保ref的值与User模型的名称完全一致(区分大小写)。
  4. 查看数据库保存错误日志

    • 在saveDeck.js的catch块中打印详细错误,排查是否存在字段类型不匹配或必填项缺失:
      catch (err) {
        console.error("卡组保存错误:", err);
        res.status(500).json({ message: "保存失败", error: err.message });
      }
      
  5. 确认用户已存入数据库

    • 检查MongoDB的users集合,确保登录用户已被正确创建,且其id(或_id)与Session中的值一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 04:20:33