Next-Auth JWT令牌未携带Role,中间件RBAC失效问题排查
Next.js + Drizzle ORM + Supabase + Auth.js RBAC 角色字段无法在JWT/中间件中获取
问题
在Next.js应用中使用Drizzle ORM、Supabase(Postgres)和Auth.js实现基于角色的访问控制(RBAC),采用Google作为OAuth提供商。目前中间件中request.auth.user.role始终为undefined,JWT令牌里也缺失role字段,尽管已在Auth.js的JWT和session回调中尝试赋值。
配置情况
- 扩展了Auth.js的
User和Session接口,新增role字段 - Auth.ts中配置了DrizzleAdapter、JWT和session回调,尝试将用户的
role传递到令牌和会话中 - Middleware.ts使用
auth()中间件根据角色实现跳转逻辑
代码片段
JWT回调
callbacks: { async jwt({ token, user }) { if (user) { token.role = user.role; // 此处赋值逻辑存在,但最终token无role token.id = user.id; } return token; }, async session({ session, token }) { session.user.role = token.role; // 尝试传递role到会话 return session; } }
中间件逻辑
const role = request.auth?.user?.role; // 🚨 始终为undefined
已检查内容
- 数据库
user表存在role列(已通过Supabase验证) - DrizzleAdapter已正确关联Supabase schema
- 会话策略设置为
"jwt"
解决方案
1. 确认TypeScript接口扩展的正确性
确保在@auth/core/types的类型扩展中正确添加role字段,让Auth.js能识别自定义字段:
import { DefaultSession, DefaultUser } from "@auth/core/types"; declare module "@auth/core/types" { interface User extends DefaultUser { role: string; } interface Session extends DefaultSession { user: User; } }
将这段代码放在Auth.ts文件顶部或单独的types/auth.d.ts文件中,确保TypeScript编译时能加载该类型扩展。
2. 验证JWT回调中user对象是否包含role
用户首次登录时,Auth.js的user参数来自DrizzleAdapter返回的数据。需要确认:
- OAuth登录后创建用户时,数据库中
user表的role字段已被正确赋值(比如设置默认值'user') - Drizzle的user表schema中
role字段不是可选类型或有默认值 - 在JWT回调中打印
user对象,确认是否包含role:async jwt({ token, user }) { console.log('JWT回调中的user对象:', user); // 检查输出是否有role字段 if (user) { token.role = user.role; token.id = user.id; } return token; },
3. 强制从数据库同步最新role到会话
如果用户role在数据库更新后JWT令牌未自动刷新,可在session回调中主动从数据库查询最新用户信息:
import { db } from '@/lib/db'; // 导入你的Drizzle数据库实例 import { users, eq } from '@/lib/db/schema'; // 导入user表schema async session({ session, token }) { if (token.id) { const dbUser = await db.query.users.findFirst({ where: eq(users.id, token.id as string), }); if (dbUser) { session.user.role = dbUser.role; } } return session; }
4. 清除旧会话缓存
旧的JWT令牌可能未包含role字段,需要让用户退出登录后重新登录,或手动清除浏览器的Auth.js相关Cookie,确保生成新的包含role的令牌。
5. 确认中间件配置正确性
确保Middleware.ts中auth()中间件的配置覆盖了需要验证的路由,且会话策略确实为"jwt":
import { auth } from "@/auth"; import { NextResponse } from "next/server"; export default auth((req) => { if (!req.auth) { return NextResponse.redirect(new URL('/login', req.url)); } const role = req.auth.user.role; // 此处添加角色权限判断逻辑 }); export const config = { matcher: ['/dashboard/:path*', '/admin/:path*'], // 按需调整匹配路径 };
内容的提问来源于stack exchange,提问作者Rana Adeel Tahir
相关产品推荐
相关产品推荐

