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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 12:10:29