在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
相关产品推荐
相关产品推荐

