Next 13客户端组件中结合Lucia Auth实现isAdmin权限校验
解决Lucia Auth管理员权限校验的方案
核心问题在于getPageSession依赖服务端专属的next/headers,不能直接在客户端组件中调用。下面是几种可行的实现方式:
方案一:服务端页面前置校验(推荐)
把权限校验逻辑放在服务端页面组件中,通过后再渲染客户端的Admin组件:
// app/admin/page.tsx(服务端组件,无需加"use client") import { redirect } from 'next/navigation'; import { getPageSession } from '@/lib/auth'; import AdminClient from './AdminClient'; export default async function AdminPage() { // 1. 校验登录状态 const session = await getPageSession(); if (!session) { redirect('/login'); } // 2. 校验管理员权限(直接在服务端查询数据库或调用内部逻辑) const userRole = await getUserRole(session.user.userId); if (userRole !== 'admin') { redirect('/login'); // 也可跳转到无权限提示页 } // 3. 权限通过,渲染客户端组件 return <AdminClient />; }
客户端组件只需专注于交互逻辑:
// app/admin/AdminClient.tsx(客户端组件) 'use client'; export default function AdminClient() { return ( <div> <h1>管理员控制台</h1> {/* 你的客户端交互内容 */} </div> ); }
方案二:全局路由中间件校验
用Next.js Middleware拦截所有/admin开头的请求,提前完成权限校验:
// middleware.ts import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; import { getPageSession } from '@/lib/auth'; export async function middleware(request: NextRequest) { if (request.nextUrl.pathname.startsWith('/admin')) { const session = await getPageSession(); // 未登录跳转登录页 if (!session) { return NextResponse.redirect(new URL('/login', request.url)); } // 非管理员跳转 const userRole = await getUserRole(session.user.userId); if (userRole !== 'admin') { return NextResponse.redirect(new URL('/login', request.url)); } // 权限通过,放行请求 return NextResponse.next(); } } // 指定拦截的路由规则 export const config = { matcher: '/admin/:path*', };
这种方式适合全局统一管控路由权限,无需在每个页面重复写校验逻辑。
方案三:客户端动态校验(Server Actions)
如果需要在客户端组件内动态校验权限(比如操作前校验),可以用Server Actions封装服务端逻辑:
// app/admin/AdminClient.tsx(客户端组件) 'use client'; import { useRouter } from 'next/navigation'; import { checkAdminPermission } from './actions'; import { useEffect } from 'react'; export default function AdminClient() { const router = useRouter(); // 组件挂载时二次校验(可选,作为服务端校验的补充) useEffect(() => { const verifyPermission = async () => { const isAdmin = await checkAdminPermission(); if (!isAdmin) router.push('/login'); }; verifyPermission(); }, [router]); return <div>管理员控制台</div>; }
封装Server Action:
// app/admin/actions.ts 'use server'; import { getPageSession } from '@/lib/auth'; export async function checkAdminPermission() { const session = await getPageSession(); if (!session) return false; const userRole = await getUserRole(session.user.userId); return userRole === 'admin'; }
内容的提问来源于stack exchange,提问作者deadcoder0904
相关产品推荐
相关产品推荐

