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

在NextJS/Prisma中为MySQL菜谱表关联用户ID外键的问题

解决NextAuth Credentials Provider会话缺失userID的问题

1. 扩展NextAuth会话,加入userID

当用户通过用户名密码登录时,在authorize回调里查询数据库拿到userID,再通过jwt和session回调把userID同步到会话中。

// app/api/auth/[...nextauth]/route.ts
import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import prisma from "@/lib/prisma";
import bcrypt from "bcrypt";

const handler = NextAuth({
  providers: [
    CredentialsProvider({
      name: "Credentials",
      credentials: {
        username: { label: "用户名", type: "text" },
        password: { label: "密码", type: "password" },
      },
      async authorize(credentials) {
        if (!credentials?.username || !credentials?.password) return null;

        // 查询用户,获取ID和加密密码
        const user = await prisma.user.findUnique({
          where: { username: credentials.username },
          select: { id: true, username: true, password: true },
        });

        if (!user) return null;

        // 验证密码
        const passwordMatch = await bcrypt.compare(credentials.password, user.password);
        if (!passwordMatch) return null;

        // 返回带ID的用户对象,后续存入token
        return { id: user.id.toString(), username: user.username };
      },
    }),
  ],
  callbacks: {
    async jwt({ token, user }) {
      // 登录时把userID写入token
      if (user) token.id = user.id;
      return token;
    },
    async session({ session, token }) {
      // 把token里的ID同步到会话
      if (session.user) session.user.id = token.id as string;
      return session;
    },
  },
  session: { strategy: "jwt" }, // Credentials Provider必须用JWT策略
});

export { handler as GET, handler as POST };

2. 扩展TypeScript类型(可选)

让TS识别会话中的userID,避免类型报错:

// types/next-auth.d.ts
import NextAuth from "next-auth";

declare module "next-auth" {
  interface User {
    id: string;
  }

  interface Session {
    user: {
      id: string;
      username: string;
    } & DefaultSession["user"];
  }
}

declare module "next-auth/jwt" {
  interface JWT {
    id: string;
  }
}

3. 创建菜谱时关联userID

在创建菜谱的API里,通过getServerSession拿到当前用户的ID,直接关联到菜谱的userId字段:

// app/api/recipes/route.ts
import { getServerSession } from "next-auth/next";
import prisma from "@/lib/prisma";
import { authOptions } from "../auth/[...nextauth]/route";
import { NextResponse } from "next/server";

export async function POST(request: Request) {
  const session = await getServerSession(authOptions);
  
  if (!session?.user?.id) {
    return NextResponse.json({ error: "未授权" }, { status: 401 });
  }

  const { title, ingredients, instructions } = await request.json();

  const recipe = await prisma.recipe.create({
    data: {
      title,
      ingredients,
      instructions,
      userId: parseInt(session.user.id), // 转成数字匹配自增ID类型
    },
  });

  return NextResponse.json(recipe);
}

4. 确认Prisma Schema关联

确保用户表和菜谱表的外键关联正确:

// prisma/schema.prisma
model User {
  id        Int      @id @default(autoincrement())
  username  String   @unique
  password  String
  recipes   Recipe[]
}

model Recipe {
  id           Int      @id @default(autoincrement())
  title        String
  ingredients  String
  instructions String
  userId       Int
  user         User     @relation(fields: [userId], references: [id], onDelete: Cascade)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 14:27:59