مجوزدهی در Next.js پس از احراز هویت انجام میشود تا مشخص شود کاربر به چه بخشهایی از اپلیکیشن دسترسی دارد. دو نوع بررسی مجوز وجود دارد:
میتوانید از فایل proxy.ts برای بررسی اولیه مجوز و ریدایرکت کاربران استفاده کنید:
// proxy.ts
import { NextRequest, NextResponse } from 'next/server'
import { decrypt } from '@/app/lib/session'
import { cookies } from 'next/headers'
const protectedRoutes = ['/dashboard']
const publicRoutes = ['/login', '/signup', '/']
export default async function proxy(req: NextRequest) {
const path = req.nextUrl.pathname
const isProtectedRoute = protectedRoutes.includes(path)
const isPublicRoute = publicRoutes.includes(path)
const cookie = (await cookies()).get('session')?.value
const session = await decrypt(cookie)
if (isProtectedRoute && !session?.userId) {
return NextResponse.redirect(new URL('/login', req.nextUrl))
}
if (isPublicRoute && session?.userId && !path.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/dashboard', req.nextUrl))
}
return NextResponse.next()
}
export const config = {
matcher: ['/((?!api|_next/static|_next/image|.*\\.png$).*)'],
}نکته: بررسیهای اصلی باید در نزدیکترین نقطه به منبع داده انجام شوند، نه فقط در Proxy.
برای متمرکزسازی منطق مجوزدهی، یک DAL بسازید که شامل تابع verifySession() باشد:
// app/lib/dal.ts
import { cookies } from 'next/headers'
import { decrypt } from '@/app/lib/session'
export const verifySession = cache(async () => {
const cookie = (await cookies()).get('session')?.value
const session = await decrypt(cookie)
if (!session?.userId) {
redirect('/login')
}
return { isAuth: true, userId: session.userId }
})سپس در درخواستهای داده از آن استفاده کنید:
export const getUser = cache(async () => {
const session = await verifySession()
if (!session) return null
const data = await db.query.users.findMany({
where: eq(users.id, session.userId),
columns: { id: true, name: true, email: true },
})
return data[0]
})برای جلوگیری از ارسال دادههای حساس به کلاینت، فقط فیلدهای مورد نیاز را بازگردانید:
// app/lib/dto.ts
import { getUser } from '@/app/lib/dal'
function canSeeUsername(viewer) {
return true
}
function canSeePhoneNumber(viewer, team) {
return viewer.isAdmin || team === viewer.team
}
export async function getProfileDTO(slug) {
const data = await db.query.users.findMany({ where: eq(users.slug, slug) })
const user = data[0]
const currentUser = await getUser(user.id)
return {
username: canSeeUsername(currentUser) ? user.username : null,
phonenumber: canSeePhoneNumber(currentUser, user.team)
? user.phonenumber
: null,
}
}در کامپوننتهای سرور میتوانید بر اساس نقش کاربر رندر شرطی انجام دهید:
// app/dashboard/page.tsx
import { verifySession } from '@/app/lib/dal'
export default async function Dashboard() {
const session = await verifySession()
const userRole = session?.user?.role
if (userRole === 'admin') {
return <AdminDashboard />
} else if (userRole === 'user') {
return <UserDashboard />
} else {
redirect('/login')
}
}به دلیل Partial Rendering، بررسی مجوز در Layout ممکن است در ناوبریهای بعدی اجرا نشود. بهتر است بررسیها را در DAL انجام دهید و دادهها را در Layout فقط fetch کنید:
// app/layout.tsx
export default async function Layout({ children }) {
const user = await getUser()
return (
// ...
)
}مجوزدهی در Next.js با ترکیب بررسی خوشبینانه، DAL، DTO و کنترل نقش در کامپوننتهای سرور قابل پیادهسازی است. این ساختار امنیت، مقیاسپذیری و نگهداری آسان را برای اپلیکیشن فراهم میکند.