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);
*/اختبر فهمك