Hazem Mohammed

Next.js 16Supabase SSRServer ActionsAuthenticationNext.js AuthTypeScriptApp Router

إتقان المصادقة في Next.js 16: دليل شامل لاستخدام Supabase SSR و Server Actions

Hazem Mohammed
٢٢ فبراير ٢٠٢٦
إتقان المصادقة في Next.js 16: دليل شامل لاستخدام Supabase SSR و Server Actions

مقدمة: تطور المصادقة في Next.js

مع تطور Next.js إلى الإصدار 16، أصبح التركيز على الأمان والأنماط التي تعتمد على الخادم (server-first) أكثر أهمية من أي وقت مضى. تشير النقاشات والمقالات لعام 2026 إلى تحول واضح بعيدًا عن إدارة الجلسات من جانب العميل نحو حلول أكثر قوة وأمانًا. في هذا الدليل التقني، سنتعمق في بناء نظام مصادقة حديث باستخدام حزمة @supabase/ssr مع قوة Server Actions في Next.js 16.

ما هو Supabase SSR ولماذا نستخدمه مع Server Actions؟

@supabase/ssr هي مكتبة مصممة خصيصًا لبيئات الخادم في Next.js. إنها تبسط بشكل كبير إدارة الجلسات والمصادقة من خلال التعامل مع الكوكيز (cookies) وتحديث الرموز المميزة (tokens) بسلاسة عبر مكونات الخادم (Server Components)، و Server Actions، وواجهات برمجة التطبيقات (API Routes)، والمزيد.

لماذا هذا المزيج قوي؟

  1. الأمان المعزز: لا يتم كشف مفاتيح العميل أو رموز الجلسة الحساسة للمتصفح أبدًا. كل منطق المصادقة يحدث على الخادم.
  2. تجربة مطور مبسطة: قل وداعًا لإدارة السياق (Context) المعقدة وحالة المصادقة من جانب العميل. يمكنك قراءة حالة المستخدم مباشرة في أي مكون خادم.
  3. تكامل سلس: تعمل Server Actions بشكل أصيل مع النماذج (Forms) وتفاعلات المستخدم، مما يجعلها الأداة المثالية لعمليات تسجيل الدخول والاشتراك.

التنفيذ: بناء تدفق مصادقة متكامل

للبدء، تأكد من تثبيت الحزم المطلوبة:

npm install @supabase/supabase-js @supabase/ssr

الخطوة 1: تهيئة عميل Supabase من جانب الخادم

نحتاج إلى إنشاء عميل Supabase يمكن استخدامه بأمان في بيئات مختلفة (مكونات العميل، مكونات الخادم، و Server Actions). سننشئ ملفًا للمساعدة في ذلك.

lib/supabase/client.ts

import { createBrowserClient } from '@supabase/ssr'

export function createClient() {
  return createBrowserClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
  )
}

lib/supabase/server.ts

import { createServerClient, type CookieOptions } from '@supabase/ssr'
import { cookies } from 'next/headers'

export function createClient() {
  const cookieStore = cookies()

  return createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: {
        get(name: string) {
          return cookieStore.get(name)?.value
        },
        set(name: string, value: string, options: CookieOptions) {
          try {
            cookieStore.set({ name, value, ...options })
          } catch (error) {
            // The `set` method was called from a Server Component.
            // This can be ignored if you have middleware refreshing user sessions.
          }
        },
        remove(name: string, options: CookieOptions) {
          try {
            cookieStore.set({ name, value: '', ...options })
          } catch (error) {
            // The `delete` method was called from a Server Component.
          }
        },
      },
    }
  )
}

الخطوة 2: حماية المسارات باستخدام Middleware

تعتبر الـ Middleware ضرورية للحفاظ على تحديث جلسة المستخدم وحماية المسارات. في Next.js 16، نستخدم اصطلاح proxy.ts لإدارة طلبات الخادم.

proxy.ts

import { createServerClient, type CookieOptions } from '@supabase/ssr'
import { NextResponse, type NextRequest } from 'next/server'

export async function middleware(request: NextRequest) {
  let response = NextResponse.next({
    request: {
      headers: request.headers,
    },
  })

  const supabase = createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: {
        get(name: string) {
          return request.cookies.get(name)?.value
        },
        set(name: string, value: string, options: CookieOptions) {
          request.cookies.set({
            name,
            value,
            ...options,
          })
          response = NextResponse.next({
            request: {
              headers: request.headers,
            },
          })
          response.cookies.set({
            name,
            value,
            ...options,
          })
        },
        remove(name: string, options: CookieOptions) {
          request.cookies.set({
            name,
            value: '',
            ...options,
          })
          response = NextResponse.next({
            request: {
              headers: request.headers,
            },
          })
          response.cookies.set({
            name,
            value: '',
            ...options,
          })
        },
      },
    }
  )

  // Refresh session if expired - crucial for Server Components
  await supabase.auth.getSession()

  return response
}

export const config = {
  matcher: [
    /*
     * Match all request paths except for the ones starting with:
     * - _next/static (static files)
     * - _next/image (image optimization files)
     * - favicon.ico (favicon file)
     * Feel free to modify this pattern to include more paths.
     */
    '/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',
  ],
}

الخطوة 3: إنشاء Server Action لتسجيل الدخول

لنقم بإنشاء نموذج تسجيل دخول يستخدم Server Action للتفاعل مع Supabase. هذا يلغي الحاجة إلى أي استدعاءات API من جانب العميل للمصادقة.

app/login/page.tsx

import { createClient } from '@/lib/supabase/server'
import { headers } from 'next/headers'
import { redirect } from 'next/navigation'

export default function LoginPage() {

  const signIn = async (formData: FormData) => {
    'use server'

    const email = formData.get('email') as string
    const password = formData.get('password') as string
    const supabase = createClient()

    const { error } = await supabase.auth.signInWithPassword({
      email,
      password,
    })

    if (error) {
      return redirect('/login?message=Could not authenticate user')
    }

    return redirect('/dashboard')
  }

  return (
    <div className="flex-1 flex flex-col w-full px-8 sm:max-w-md justify-center gap-2">
      <form action={signIn} className="flex-1 flex flex-col w-full justify-center gap-2 text-foreground">
        <label className="text-md" htmlFor="email">
          Email
        </label>
        <input
          className="rounded-md px-4 py-2 bg-inherit border mb-6"
          name="email"
          placeholder="you@example.com"
          required
        />
        <label className="text-md" htmlFor="password">
          Password
        </label>
        <input
          className="rounded-md px-4 py-2 bg-inherit border mb-6"
          type="password"
          name="password"
          placeholder="••••••••"
          required
        />
        <button className="bg-green-700 rounded px-4 py-2 text-white mb-2">
          Sign In
        </button>
      </form>
    </div>
  )
}

الخطوة 4: عرض واجهة مستخدم مشروطة وتسجيل الخروج

في مكون خادم، يمكننا الآن التحقق بسهولة من حالة مصادقة المستخدم وعرض محتوى مختلف. زر تسجيل الخروج سيستخدم أيضًا Server Action.

app/dashboard/page.tsx

import { createClient } from '@/lib/supabase/server';
import { redirect } from 'next/navigation';

export default async function DashboardPage() {
  const supabase = createClient();

  const { data, error } = await supabase.auth.getUser();
  if (error || !data?.user) {
    redirect('/login');
  }

  const signOut = async () => {
    'use server';
    const supabase = createClient();
    await supabase.auth.signOut();
    return redirect('/login');
  };

  return (
    <div>
      <p>Hello, {data.user.email}</p>
      <form action={signOut}>
        <button className="py-2 px-4 rounded-md no-underline bg-btn-background hover:bg-btn-background-hover">
          Logout
        </button>
      </form>
    </div>
  );
}

حالات الاستخدام في العالم الحقيقي

هذا النمط مثالي لأي تطبيق Next.js 16 يتطلب مصادقة المستخدم. الأمثلة تشمل:

  • لوحات تحكم SaaS: حماية صفحات لوحة التحكم والوصول إلى البيانات الخاصة بالمستخدم.
  • مواقع التجارة الإلكترونية: إدارة حسابات العملاء، سجل الطلبات، وعمليات الدفع.
  • منصات المحتوى: تقييد الوصول إلى المقالات أو الدورات المميزة للمشتركين فقط.
  • التطبيقات الاجتماعية: التعامل مع ملفات تعريف المستخدمين، والمشاركات، والتفاعلات.

الخلاصة

من خلال الجمع بين @supabase/ssr و Next.js 16 Server Actions، نقوم بإنشاء نظام مصادقة آمن للغاية وفعال وسهل الصيانة. هذا النهج الذي يركز على الخادم يتماشى تمامًا مع رؤية Next.js، مما يقلل من التعقيد من جانب العميل ويوفر أساسًا متينًا لبناء تطبيقات ويب حديثة وقوية.

HM

Hazem Mohammed

مطور ويب متخصص في هندسة تطبيقات حديثة، سريعة، وقابلة للتوسع.