Supabase Rôles et Permissions : Gérer les Accès avec PostgreSQL

Au-delà de la RLS, Supabase permet de gérer des systèmes de rôles sophistiqués (admin, moderateur, user, etc.) en combinant PostgreSQL, les JWT tokens et les policies. Voici comment construire un système de permissions robuste.

Pour le contexte global, consulte notre guide complet Supabase. Pour les bases de la sécurité, lis Supabase RLS : Row Level Security. Pour les tokens JWT, voir Supabase Auth. Pour les migrations de ta table permissions, voir Supabase Migrations.

Les Rôles PostgreSQL dans Supabase

Supabase crée 4 rôles PostgreSQL par défaut :

Rôle Description Usage
anon Utilisateurs non connectés API publique
authenticated Utilisateurs connectés API sécurisée
service_role Accès complet (bypass RLS) Backend serveur uniquement
postgres Superuser PostgreSQL Migrations, administration

Implémenter un Système de Rôles Applicatifs

Étape 1 : Ajouter un champ rôle au profil

-- Créer un type ENUM pour les rôles
CREATE TYPE user_role AS ENUM ('user', 'moderator', 'admin');

-- Ajouter à la table profiles
ALTER TABLE profiles ADD COLUMN role user_role DEFAULT 'user';

-- Index pour les performances
CREATE INDEX idx_profiles_role ON profiles(role);

Étape 2 : Fonctions helper pour les policies

CREATE OR REPLACE FUNCTION is_admin()
RETURNS BOOLEAN AS $$
  SELECT EXISTS (
    SELECT 1 FROM profiles
    WHERE id = auth.uid() AND role = 'admin'
  );
$$ LANGUAGE sql STABLE SECURITY DEFINER;

CREATE OR REPLACE FUNCTION is_moderator_or_above()
RETURNS BOOLEAN AS $$
  SELECT EXISTS (
    SELECT 1 FROM profiles
    WHERE id = auth.uid() 
    AND role IN ('moderator', 'admin')
  );
$$ LANGUAGE sql STABLE SECURITY DEFINER;

Étape 3 : Policies basées sur les rôles

ALTER TABLE comments ENABLE ROW LEVEL SECURITY;

CREATE POLICY "comments_public_read"
ON comments FOR SELECT USING (true);

CREATE POLICY "authenticated_create_comments"
ON comments FOR INSERT
TO authenticated
WITH CHECK (auth.uid() = user_id);

CREATE POLICY "users_or_mods_delete_comments"
ON comments FOR DELETE
TO authenticated
USING (auth.uid() = user_id OR is_moderator_or_above());

Rôles via JWT Claims Personnalisés

CREATE OR REPLACE FUNCTION public.custom_access_token_hook(event JSONB)
RETURNS JSONB AS $$
DECLARE
  claims JSONB;
  user_role_value user_role;
BEGIN
  SELECT role INTO user_role_value
  FROM profiles
  WHERE id = (event->>'user_id')::UUID;
  
  claims := event->'claims';
  claims := jsonb_set(claims, '{user_role}', to_jsonb(user_role_value::TEXT));
  
  RETURN jsonb_set(event, '{claims}', claims);
END;
$$ LANGUAGE plpgsql STABLE SECURITY DEFINER;

Permissions Granulaires avec des Tables de Permissions

CREATE TABLE permissions (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  name TEXT UNIQUE NOT NULL,
  description TEXT
);

CREATE TABLE role_permissions (
  role user_role NOT NULL,
  permission_id UUID REFERENCES permissions(id),
  PRIMARY KEY (role, permission_id)
);

Afficher le Rôle côté Frontend

export function useRole() {
  const user = useUser()
  const [role, setRole] = useState(null)
  
  useEffect(() => {
    if (!user) return
    
    supabase
      .from('profiles')
      .select('role')
      .eq('id', user.id)
      .single()
      .then(({ data }) => setRole(data?.role ?? 'user'))
  }, [user])
  
  return {
    role,
    isAdmin: role === 'admin',
    isModerator: role === 'moderator' || role === 'admin',
  }
}

👉 Articles du guide Supabase

Cet article fait partie du Guide Complet Supabase 2026. Retrouvez les autres articles :

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *