مجوزدهی در Next.js – بررسی خوش‌بینانه، لایه دسترسی داده، و کنترل نقش کاربر

پس از احراز هویت و ایجاد نشست، می‌توان با استفاده از مجوزدهی در Next.js کنترل کرد که کاربر به چه مسیرها و داده‌هایی دسترسی دارد. این مقاله انواع بررسی مجوز، استفاده از Proxy برای بررسی خوش‌بینانه، ساخت لایه دسترسی داده (DAL)، استفاده از DTO برای ایمن‌سازی داده‌ها، و کنترل نقش کاربر در کامپوننت‌های سرور را بررسی می‌کند.

~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 و کنترل نقش در کامپوننت‌های سرور قابل پیاده‌سازی است. این ساختار امنیت، مقیاس‌پذیری و نگهداری آسان را برای اپلیکیشن فراهم می‌کند.


نوشته و پژوهش شده توسط دکتر شاهین صیامی