Next.js中结合Auth.js、Mongoose与Google OAuth实现RBAC时出现语法报错求助
Next.js中结合Auth.js、Mongoose与Google OAuth实现RBAC时出现语法报错求助
看起来你遇到的语法报错大概率是代码里的语法不完整导致的,我先帮你排查下你贴出来的代码里的问题,再给你补充下RBAC实现的关键步骤:
1. 先修复触发“Expression expected”的核心语法错误
看你Google Provider的profile函数里的返回语句:
return { role: profile.role ?? "user", ...}
这里的...}是不完整的语法——扩展运算符...后面必须跟要展开的对象(也就是你要把Google返回的profile其他属性整合到返回的用户对象里),JS解析器在这里期望看到一个表达式,结果你只写了...,所以直接抛出了“Expression expected”的错误。
正确的写法应该是把profile的必要属性展开或显式声明,比如:
Google({ profile(profile) { return { id: profile.sub, // Google profile里的用户唯一ID是sub字段 name: profile.name, email: profile.email, image: profile.picture, role: profile.role ?? "user" // 给默认角色user }; // 或者直接展开整个profile再覆盖role: // return { ...profile, role: profile.role ?? "user", id: profile.sub }; } }),
2. 完善Callbacks,从Mongoose数据库同步用户角色到Session
你的需求是根据数据库里的用户角色控制页面访问,所以需要在session回调里从MongoDB查询用户的实际角色,再把它加到session中,这样前端和Middleware才能拿到角色信息:
首先把callbacks整合到你的authConfig里(不要分开写),完整的authConfig示例:
import Google from "next-auth/providers/google"; import type { NextAuthConfig } from "next-auth"; import User from "@/models/User"; // 导入你的Mongoose User模型 export default { providers: [ Google({ clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, profile(profile) { return { id: profile.sub, name: profile.name, email: profile.email, image: profile.picture, role: "user" // 先给默认值,后续从数据库覆盖 }; } }), ], callbacks: { // 首次登录时把用户信息同步到数据库(可选,根据你的需求) async signIn({ user, account, profile }) { // 检查用户是否已存在于数据库,不存在则创建 const existingUser = await User.findOne({ email: user.email }); if (!existingUser) { await User.create({ email: user.email, name: user.name, role: "user" // 默认角色,后续可以在后台修改 }); } return true; }, async session({ session, token }) { // 从数据库查询当前用户的真实角色 const userFromDb = await User.findOne({ email: session.user.email }); if (userFromDb) { session.user.role = userFromDb.role ?? "user"; } return session; }, async jwt({ token, user }) { // 首次登录时把用户角色存入token,避免重复查库(可选优化) if (user) { token.role = user.role; } return token; } } } satisfies NextAuthConfig;
3. 修正Middleware的写法
Auth.js v5推荐更简洁的Middleware导出方式,你可以改回:
export { auth as middleware } from "@/auth";
如果需要自定义路由保护逻辑(比如根据角色拦截路由),可以扩展Middleware:
import { auth } from "@/auth"; import { NextResponse } from "next/server"; export default async function middleware(req) { const session = await auth(req); const path = req.nextUrl.pathname; // 示例:/admin开头的路由仅允许admin角色访问 if (path.startsWith("/admin") && session?.user?.role !== "admin") { return NextResponse.redirect(new URL("/", req.nextUrl.origin)); } // 示例:未登录用户无法访问/dashboard路由 if (path.startsWith("/dashboard") && !session) { return NextResponse.redirect(new URL("/login", req.nextUrl.origin)); } } // 指定需要应用Middleware的路由匹配规则 export const config = { matcher: ["/admin/:path*", "/dashboard/:path*"], };
4. 验证修复效果
当你修复了语法错误并完善上述代码后,再启动项目,之前的“Expression expected”报错应该会消失,同时session里的user对象会带上从数据库获取的role属性,你可以在前端通过useSession()或者后端通过auth()拿到这个角色,实现基于角色的访问控制。
备注:内容来源于stack exchange,提问作者Febry Aryo
相关产品推荐
相关产品推荐

