Mise en place des RLS
Sécuriser l’accès aux données selon le rôle de l’utilisateur
Notions théoriques
Qu’est-ce que le Row Level Security (RLS) ?
Le Row Level Security (RLS) est une fonctionnalité de PostgreSQL (et donc de Supabase) qui permet de restreindre l’accès aux lignes d’une table en fonction de l’utilisateur connecté.
Il ne s’agit pas seulement de masquer des colonnes ou de bloquer des tables entières, mais bien de filtrer ligne par ligne ce qu’un utilisateur peut voir, insérer, modifier ou supprimer.
RLS est un outil essentiel pour éviter les fuites de données dans les applications multi-utilisateurs.
RLS doit être activé explicitement sur chaque table où l’on souhaite l’utiliser.
Pourquoi activer RLS ?
Par défaut, toutes les lignes d’une table sont visibles si un utilisateur a la permission de faire un SELECT.
Cela pose problème dans une application avec différents rôles (guest, student, teacher, admin, super-admin).
Avec RLS, on peut dire :
- un
guestne voit que son propre profil, - un
studentne peut écrire des messages que dans ses classes, - un
teacherpeut voir les membres de ses classes, - un
adminpeut modifier toutes les classes, - un
super-adminpeut tout faire.
Activer RLS sur une table
Pour activer RLS sur une table dans Supabase :
ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;
Supabase n’applique aucune restriction par défaut après activation.
Il faut ajouter des politiques (POLICY) pour définir ce qui est autorisé.
Ajouter une politique RLS
Une politique est une règle SQL qui s’applique à un type d’opération : SELECT, INSERT, UPDATE, ou DELETE.
Exemple : autoriser un utilisateur à voir son propre profil :
create policy "Un utilisateur peut voir son propre profil"
on profiles
for select
using (auth.uid() = id);
Explication :
auth.uid()est l’ID de l’utilisateur connecté.idest la clé primaire deprofiles, qui référenceauth.users.id.
Exemple de politique INSERT : écrire un message uniquement si on est membre d’une classe
create policy "Un utilisateur peut écrire un message dans une classe à laquelle il appartient"
on messages
for insert
with check (
exists (
select 1 from class_members
where class_id = messages.class_id
and user_id = auth.uid()
)
);
Tester les politiques
Il est possible de simuler un utilisateur dans l’éditeur SQL Supabase :
set role authenticated;
set local jwt.claims.sub = 'uuid-de-l-utilisateur';
Cela permet de tester les effets d’une politique comme si on était connecté avec un rôle donné.
Bonnes pratiques avec RLS
Toujours activer RLS avant de déployer une application multi-utilisateurs.
Créer des politiques pour chaque opération (SELECT, INSERT, UPDATE, DELETE).
Tester les politiques avec différents rôles pour éviter les fuites accidentelles.
Ne jamais supposer que les utilisateurs vont se limiter à l’interface prévue. Ils peuvent envoyer des requêtes SQL directement (via API ou outils comme DBeaver).
Exemple pratique
Il est possible de sécuriser la table profiles pour que :
- un utilisateur ne voie que son propre profil,
- un
adminousuper-adminvoie tous les profils.
Étape 1 : activer RLS sur la table profiles
alter table profiles enable row level security;
Étape 2 : autoriser un utilisateur à voir son propre profil
create policy "lecture de son propre profil"
on profiles
for select
using (auth.uid() = id);
Étape 3 : autoriser les admins à voir tous les profils
create policy "lecture pour les admins"
on profiles
for select
using (
exists (
select 1 from user_roles
where user_id = auth.uid()
and role in ('admin', 'super-admin')
)
);
Étape 4 : tester avec un utilisateur simulé
set role authenticated;
set local jwt.claims.sub = 'uuid-du-student';
select * from profiles;
Résultat : l’étudiant ne voit que sa propre ligne.
Changer l’UUID pour celui d’un admin : il verra tous les profils.
Test de mémorisation/compréhension
TP pour réfléchir et résoudre des problèmes
Ce TP a pour objectif de mettre en place des politiques Row Level Security (RLS) sur les tables existantes de votre BD Supabase,
en appliquant des restrictions d'accès selon les rôles définis dans la table user_roles.
Étape 1 : Activer RLS sur la table profiles
Dans l’éditeur SQL de Supabase, activer RLS sur la table profiles.
ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;
Une solution
Vous devez être connecté pour voir le contenu.
Étape 2 : Créer une politique RLS pour permettre à un utilisateur de voir uniquement son propre profil
Créer une politique SELECT qui autorise un utilisateur à voir uniquement sa propre ligne dans la table profiles.
CREATE POLICY "lecture de son propre profil"
ON profiles
FOR SELECT
USING (auth.uid() = id);
Une solution
Vous devez être connecté pour voir le contenu.
Étape 3 : Créer une politique RLS permettant aux administrateurs de voir tous les profils
Créer une politique SELECT qui autorise les utilisateurs ayant le rôle admin ou super-admin à voir tous les profils.
CREATE POLICY "lecture pour les admins"
ON profiles
FOR SELECT
USING (
EXISTS (
SELECT 1 FROM user_roles
WHERE user_id = auth.uid()
AND role IN ('admin', 'super-admin')
)
);
Une solution
Vous devez être connecté pour voir le contenu.
Étape 4 : Tester les politiques avec un utilisateur simulé
Simuler une session avec un utilisateur ayant un rôle student (ou autre) pour vérifier que les politiques fonctionnent.
SET ROLE authenticated;
SET LOCAL jwt.claims.sub = 'uuid-de-l-utilisateur';
SELECT * FROM profiles;
Changer l’UUID pour tester différents cas :
- UUID d’un
guest→ ne doit voir que sa ligne - UUID d’un
admin→ doit voir tous les profils
Une solution
Vous devez être connecté pour voir le contenu.
Étape 5 : Créer une politique RLS pour permettre aux utilisateurs de modifier uniquement leur propre profil
Créer une politique UPDATE qui autorise un utilisateur à modifier uniquement sa propre ligne.
CREATE POLICY "modification de son propre profil"
ON profiles
FOR UPDATE
USING (auth.uid() = id);
Une solution
Vous devez être connecté pour voir le contenu.
Étape 6 : Créer une politique RLS permettant aux administrateurs de modifier tous les profils
Créer une politique UPDATE qui autorise les admin et super-admin à modifier n’importe quel profil.
CREATE POLICY "modification pour les admins"
ON profiles
FOR UPDATE
USING (
EXISTS (
SELECT 1 FROM user_roles
WHERE user_id = auth.uid()
AND role IN ('admin', 'super-admin')
)
);
Une solution
Vous devez être connecté pour voir le contenu.
Étape 7 : créer une politique RLS pour interdire les suppressions sauf pour les super-admins
Créer une politique DELETE qui autorise uniquement les super-admin à supprimer un profil.
CREATE POLICY "suppression réservée aux super-admins"
ON profiles
FOR DELETE
USING (
EXISTS (
SELECT 1 FROM user_roles
WHERE user_id = auth.uid()
AND role = 'super-admin'
)
);
Une solution
Vous devez être connecté pour voir le contenu.
Étape 8 : Tester les politiques UPDATE et DELETE avec différents utilisateurs
Simuler une session avec un student, un teacher, un admin et un super-admin. Tester les opérations suivantes :
UPDATEsur sa propre ligneUPDATEsur une autre ligneDELETEsur sa propre ligneDELETEsur une autre ligne
Utiliser les commandes :
SET ROLE authenticated;
SET LOCAL jwt.claims.sub = 'uuid-de-l-utilisateur';
Puis effectuer une requête comme :
UPDATE profiles
SET username = 'nouveau_nom'
WHERE id = 'uuid-d-un-autre-user';
Et :
DELETE FROM profiles
WHERE id = 'uuid-d-un-autre-user';
Une solution
Vous devez être connecté pour voir le contenu.