request.auth.user.role
是未定义的)。 我正在使用Google作为Oauth提供商
SETUP:
authconfig
:扩展User
Session
接口,包括role
。
auth.ts:配置了drizzleadapter,jwt和会话回调,从用户到令牌和会话传播。
role
中间件基于角色重定向。
auth()
token.role
和会话数据并未填充用户的角色。在中间件中,尽管在回调中分配了request.auth?.user?.role
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;
}
}
const role = request.auth?.user?.role; // 🚨 Always undefined
files
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
});
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
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验证)。
Session策略:设置为
role
。
问题: 为什么"jwt"
问题并不是NextAuth无法将角色存储在令牌中,而是使用与主要NextAuth实例不同的中间软件。我两次实例化NextAuth,我的中间件没有看到JWT和会话回调,将角色添加到令牌中。
role
-later,我的会话回调将此值复制到会话中。但是,在中间件中,我调用没有其他回调的配置(例如,导入authconfig)的NextAuth。结果,在那里使用的JWT令牌不包括角色,因此Soif (user) token.role = user.role;
社区中的其他人确认了这种行为,例如,几个GitHub讨论(在中间件中,不会使用自定义字段扩展会话] [1]说明,在API路线中使用不同的NextAuth使用不同的实例化/配置导致缺少自定义字段。 fix
i我将我的下一个配置合并为一个地方。i将我的整个NextAuth配置放在单个文件中(例如
,然后在我的主验证文件(例如,
auth.config.ts
auth.ts
,
auth
,
signIn
,等)。
最终,在中间件中,我导入并使用了相同的实例化助手,而不是通过部分配置重新引导NextAuth。现在我的文件看起来像这样:
signOut
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令牌。