~4 دقیقه مطالعه • بروزرسانی ۴ آبان ۱۴۰۴
مقدمه
مجوزدهی در Next.js پس از احراز هویت انجام میشود تا مشخص شود کاربر به چه بخشهایی از اپلیکیشن دسترسی دارد. دو نوع بررسی مجوز وجود دارد:
- بررسی خوشبینانه: با استفاده از دادهٔ نشست در کوکی انجام میشود و برای عملیات سریع مانند نمایش/مخفیسازی عناصر UI مناسب است.
- بررسی امن: با استفاده از دادهٔ نشست در پایگاهداده انجام میشود و برای عملیات حساس توصیه میشود.
بررسی خوشبینانه با Proxy
میتوانید از فایل 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)
برای متمرکزسازی منطق مجوزدهی، یک 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]
})استفاده از DTO برای ایمنسازی دادهها
برای جلوگیری از ارسال دادههای حساس به کلاینت، فقط فیلدهای مورد نیاز را بازگردانید:
// 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')
}
}نکته درباره Layoutها
به دلیل Partial Rendering، بررسی مجوز در Layout ممکن است در ناوبریهای بعدی اجرا نشود. بهتر است بررسیها را در DAL انجام دهید و دادهها را در Layout فقط fetch کنید:
// app/layout.tsx
export default async function Layout({ children }) {
const user = await getUser()
return (
// ...
)
}جمعبندی
مجوزدهی در Next.js با ترکیب بررسی خوشبینانه، DAL، DTO و کنترل نقش در کامپوننتهای سرور قابل پیادهسازی است. این ساختار امنیت، مقیاسپذیری و نگهداری آسان را برای اپلیکیشن فراهم میکند.
نوشته و پژوهش شده توسط دکتر شاهین صیامی