I'M使用Drizzle Orm,Supabase(Postgres)和Auth.js在Next.js应用中实现基于角色的访问控制。我的中间件没有从JWT令牌(request.auth.user ....

问题描述 投票:0回答:1
request.auth.user.role

是未定义的)。 我正在使用Google作为Oauth提供商

SETUP

authconfig

:扩展
    User
  • Session接口,包括
    role
    auth.ts
    :配置了drizzleadapter,jwt和会话回调,从用户到令牌和会话传播。
    
  • Middleware.ts
  • :使用role中间件基于角色重定向。
  • sissue
  • : JWT回调的auth()
    token.role
    和会话数据并未填充用户的角色。在中间件中,尽管在回调中分配了
  • request.auth?.user?.role
log作为

undefined。 JWT令牌显示role

缺少。
代码片段

jwt回调:

callbacks: { async jwt({ token, user }) { if (user) { token.role = user.role; // Here it's ok token.id = user.id; } return token; }, async session({ session, token }) { session.user.role = token.role; // Propagates to session return session; } }

  1. Middleware逻辑:
  2. const role = request.auth?.user?.role; // 🚨 Always undefined
files
  1. auth.ts
  2. import { DrizzleAdapter } from "@auth/drizzle-adapter"; import { db } from "@/drizzle/db" import authConfig from "./auth.config"; import NextAuth from "next-auth"; import { accounts, sessions, user, verificationTokens } from "@/drizzle/schema"; export const { handlers, auth, signIn, signOut } = NextAuth({ adapter: DrizzleAdapter(db, { usersTable: user, accountsTable: accounts, sessionsTable: sessions, verificationTokensTable: verificationTokens, } ), session: { strategy: "jwt" }, callbacks: { async jwt({ token, user }) { try { if (user) { token.role = user.role token.id = user.id } return token; } catch (error) { console.error('Error in jwt callback:', error); return token; } }, async session({ session, token }) { try { session.user.role = token.role; session.user.id = token.id; return session; } catch (error) { console.error('Error in session callback:', error); return session; } } }, ...authConfig });
auth.config.ts

import { DefaultSession, NextAuthConfig } from "next-auth"; import Google from "next-auth/providers/google" declare module "next-auth" { interface User { role?: string; } interface Session extends DefaultSession { user: { role?: string; } & DefaultSession["user"]; } } export default { providers: [ Google({ profile(profile) { console.log("Profile in Provider", profile) return { id: profile.sub, name: profile.name, email: profile.email, image: profile.picture, }; }, }), ], } satisfies NextAuthConfig

Middleware.ts

import authConfig from "./auth.config" import NextAuth from "next-auth" const { auth } = NextAuth(authConfig) export default auth((request) => { // Your custom middleware logic goes here const isLoggedIn = !!request.auth; const url = new URL(request.url); const role = request.auth?.user?.role; console.log("Middleware User", request.auth?.user) console.log("User role", request.auth?.user?.role) if (!isLoggedIn && url.pathname !== "/") { return NextResponse.redirect(new URL("/", url.origin)); } else if (isLoggedIn && role === "admin" && url.pathname !== "/Admin") { return NextResponse.redirect(new URL("/Admin", url.origin)); } else if (isLoggedIn && role === "employee" && url.pathname !== "/Employee") { return NextResponse.redirect(new URL("/Employee", url.origin)); } else if (isLoggedIn && role === "manager" && url.pathname !== "/Manager") { return NextResponse.redirect(new URL("/Manager", url.origin)); } else if (isLoggedIn && role == "none" && url.pathname !== "/auth") { return NextResponse.redirect(new URL("/auth", url.origin)); } }); export const config = { matcher: [ "/((?!api|_next/static|_next/image|favicon.ico).*)", ], };

我检查了什么:

database:user表有一个列列(通过supabase验证)。

适配器:毛毛球运动员正确链接到supabase架构。
Session策略:设置为
role

问题: 为什么
    "jwt"
  • 领域不在JWT/Session中持续存在,我该如何确保它在中间件中可以访问?回调或适配器设置中是否缺少配置?
        
    问题并不是NextAuth无法将角色存储在令牌中,而是使用与主要NextAuth实例不同的中间软件。我两次实例化NextAuth,我的中间件没有看到JWT和会话回调,将角色添加到令牌中。
    
  • 发生了什么
  • 当用户登录时,JWT回调运行并设置:
  • role
     -later,我的会话回调将此值复制到会话中。但是,在中间件中,我调用没有其他回调的配置(例如,导入authconfig)的NextAuth。结果,在那里使用的JWT令牌不包括角色,因此So
  • if (user) token.role = user.role;
仍然不确定。

社区中的其他人确认了这种行为,例如,几个GitHub讨论(在中间件中,不会使用自定义字段扩展会话] [1]说明,在API路线中使用不同的NextAuth使用不同的实例化/配置导致缺少自定义字段。 fix

i我将我的下一个配置合并为一个地方。

i将我的整个NextAuth配置放在单个文件中(例如
authentication next.js middleware next-auth drizzle
1个回答
0
投票
)中。

,然后在我的主验证文件(例如,

auth.config.ts

)中,我用这种单个配置实例化了NextAuth,并导出了助手功能(例如

auth.ts

auth
signIn

,等)。

最终,在中间件中,我导入并使用了相同的实例化助手,而不是通过部分配置重新引导NextAuth。

现在我的文件看起来像这样:

auth.config.ts

signOut

    auth.ts
  • import { NextAuthConfig } from "next-auth";
    import GoogleProvider from "next-auth/providers/google";
    
    
    const authConfig: NextAuthConfig = {
      providers: [
        GoogleProvider({
          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" };
          },
        }),
      ],
      session: { strategy: "jwt" },
      callbacks: {
        async jwt({ token, user }) {
          // On sign in, user is available
          if (user) {
            token.role = user.role; // Add role to token
          }
          return token;
        },
        async session({ session, token }) {
          // Make sure role is available in session.user
          if (session.user) {
            session.user.role = token.role;
          }
          return session;
        },
      },
      secret: process.env.NEXTAUTH_SECRET,
    };
    
    export default authConfig;
    
  • Middleware.ts
    import NextAuth from "next-auth";
    import authConfig from "./auth.config";
    
    // Single instantiation of NextAuth with full configuration
    export const { handlers, auth, signIn, signOut } = NextAuth(authConfig);
    
    为什么这起作用
    
    通过使用单个统一的NextAuth实例化,我确保我的应用程序的每个部分都包括MiddlewareHas访问包括角色的修改后的JWT令牌。
        
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.