Kodax

Authentication مع Supabase — Supabase

المصادقة و RLS في Supabase

التسجيل والدخول

import { supabase } from "./supabaseClient.js";

export async function signUp(email, password) {
  const { data, error } = await supabase.auth.signUp({ email, password });
  if (error) throw error;
  return data.user;          // قد يحتاج تأكيد البريد قبل أن تصبح الجلسة فعالة
}

export async function signIn(email, password) {
  const { data, error } = await supabase.auth.signInWithPassword({ email, password });
  if (error) throw error;
  return data.session;
}

- signInWithOAuth({ provider: "google" }): الدخول بمزود خارجي (يُضبط في لوحة Supabase).

- signInWithOtp({ email }): رابط سحري بلا كلمة مرور.

- signOut(): الخروج.

المستخدم الحالي

| الدالة | متى |

|---|---|

| supabase.auth.getSession() | قراءة الجلسة المحفوظة محلياً (سريع) — للواجهة |

| supabase.auth.getUser() | يتحقق من الرمز مع خادم Supabase — استخدمه على الخادم قبل الوثوق بالهوية |

| onAuthStateChange(cb) | الاستماع للدخول والخروج وتجديد الرمز — حدّث واجهتك منه |

onAuthStateChange يعيد اشتراكاً: ألغه عند تفكيك المكوّن (data.subscription.unsubscribe()).

RLS: أهم شيء في Supabase

لأن الواجهة تتصل بقاعدة البيانات مباشرة بمفتاح anon العلني، سياسات أمان مستوى الصفوف (Row Level Security) هي ما يمنع مستخدماً من قراءة بيانات غيره أو حذفها.

-- 1) فعّل RLS — بدونه يقرأ ويكتب أي شخص يملك مفتاح anon كل الجدول
ALTER TABLE todos ENABLE ROW LEVEL SECURITY;

-- 2) سياسة لكل عملية
CREATE POLICY "read own todos" ON todos
  FOR SELECT USING (auth.uid() = user_id);

CREATE POLICY "insert own todos" ON todos
  FOR INSERT WITH CHECK (auth.uid() = user_id);

CREATE POLICY "update own todos" ON todos
  FOR UPDATE USING (auth.uid() = user_id) WITH CHECK (auth.uid() = user_id);

CREATE POLICY "delete own todos" ON todos
  FOR DELETE USING (auth.uid() = user_id);

| الجزء | المعنى |

|---|---|

| USING | أي الصفوف الموجودة يمكن رؤيتها/تعديلها/حذفها |

| WITH CHECK | هل القيم الجديدة مسموحة (عند الإدراج والتحديث) |

| auth.uid() | معرّف المستخدم من الرمز المرسل |

بدون WITH CHECK في سياسة التحديث، يستطيع المستخدم تعديل صفه وتغيير user_id إلى مستخدم آخر.

قواعد ذهبية

- RLS مفعّل على كل جدول في مخطط public — Supabase يحذرك في لوحة Security Advisor.

- مع RLS مفعّل وبلا سياسات = لا شيء مسموح (رفض افتراضي). أضف السياسات تدريجياً.

- user_id افتراضيه auth.uid() (DEFAULT auth.uid()) ولا تثق بقيمة يرسلها العميل.

- اختبر السياسات من حسابين مختلفين: هل يرى المستخدم ب بيانات المستخدم أ؟

تمرين

فعّل RLS على جدول todos من الدرس السابق مع السياسات الأربع، وأضف عمود user_id uuid DEFAULT auth.uid(). سجّل الدخول بحسابين تجريبيين وتحقق أن كلاً منهما يرى مهامه فقط.

// auth.js — المصادقة مع supabase-js v2
import { supabase } from "./supabaseClient.js";

export async function signUp(email, password) {
  const { data, error } = await supabase.auth.signUp({ email, password });
  if (error) throw error;
  return data.user;
}

export async function signIn(email, password) {
  const { data, error } = await supabase.auth.signInWithPassword({ email, password });
  if (error) throw error;     // رسالة موحدة للمستخدم: "بيانات الدخول غير صحيحة"
  return data.session;
}

export async function signInWithGoogle() {
  const { error } = await supabase.auth.signInWithOAuth({
    provider: "google",
    options: { redirectTo: window.location.origin + "/auth/callback" },
  });
  if (error) throw error;
}

export async function signOut() {
  const { error } = await supabase.auth.signOut();
  if (error) throw error;
}

// الاستماع لتغيّر الجلسة — أعد الدالة لإلغاء الاشتراك عند تفكيك المكوّن
export function watchAuth(onChange) {
  const { data } = supabase.auth.onAuthStateChange((event, session) => {
    onChange(event, session?.user ?? null);
  });
  return () => data.subscription.unsubscribe();
}

/* ===== في SQL Editor =====
ALTER TABLE todos ADD COLUMN user_id uuid NOT NULL DEFAULT auth.uid() REFERENCES auth.users(id) ON DELETE CASCADE;
ALTER TABLE todos ENABLE ROW LEVEL SECURITY;

CREATE POLICY "read own"   ON todos FOR SELECT USING (auth.uid() = user_id);
CREATE POLICY "insert own" ON todos FOR INSERT WITH CHECK (auth.uid() = user_id);
CREATE POLICY "update own" ON todos FOR UPDATE USING (auth.uid() = user_id) WITH CHECK (auth.uid() = user_id);
CREATE POLICY "delete own" ON todos FOR DELETE USING (auth.uid() = user_id);
*/
اختبر فهمك