Aller au contenu principal

Table profils / rôles

Création de la table de relation entre utilisateurs et rôles

Notions théoriques

Le type ENUM pour les rôles

Pourquoi utiliser un type ENUM pour les rôles ?

Dans une base de données relationnelle comme PostgreSQL (et donc Supabase), il est souvent nécessaire de limiter les valeurs possibles d’un champ à un ensemble précis.

C’est exactement ce que permet un type ENUM : un type personnalisé qui restreint les valeurs à une liste définie.

Dans notre projet, les utilisateurs peuvent avoir différents rôles :

  • guest
  • student
  • teacher
  • admin
  • super-admin

Ces rôles ont des droits différents dans l’application. Il est donc important de les gérer de manière fiable et sécurisée.


Avantages d’un type ENUM

  • Validation automatique : PostgreSQL empêche l’insertion d’une valeur non prévue.
  • Lisibilité : les valeurs sont explicites et claires ('admin', 'student', etc.).
  • Sécurité : impossible d’ajouter un rôle non prévu par erreur.
  • Compatibilité avec Supabase : les types ENUM sont bien pris en charge dans l’interface.
astuce

Toujours préférer un type ENUM à une simple colonne texte quand les valeurs possibles sont connues et limitées.


Définition d’un type ENUM

Voici comment créer un type ENUM dans PostgreSQL :

create type user_role as enum ('guest', 'student', 'teacher', 'admin', 'super-admin');

Cette commande crée un nouveau type user_role avec cinq valeurs autorisées.


Créer la table user_roles

Créer une table pour stocker les rôles des utilisateurs

Une fois le type ENUM créé, on peut l’utiliser dans une table.
La table user_roles permet de lier un utilisateur à un rôle donné.

Structure de la table :

ColonneTypeDescription
iduuidIdentifiant unique (clé primaire)
user_iduuidRéférence à auth.users(id)
roleuser_roleRôle de l’utilisateur
created_attimestamp with time zoneDate de création de la ligne
updated_attimestamp with time zoneDate de dernière mise à jour

Script SQL pour créer la table

create table public.user_roles (
id uuid default uuid_generate_v4() primary key,
user_id uuid references auth.users(id) not null,
role user_role not null default 'guest',
created_at timestamp with time zone default current_timestamp,
updated_at timestamp with time zone default current_timestamp
);
info

Le champ role utilise le type user_role défini précédemment.

La valeur par défaut est 'guest'.


Bonnes pratiques cyber

  • Limiter les rôles possibles via un ENUM empêche les erreurs ou attaques par injection de rôles non autorisés.
  • Auditer les changements de rôle : les champs created_at et updated_at permettent de tracer les modifications.
  • Éviter les valeurs libres : ne jamais autoriser un champ texte libre pour des rôles critiques.
attention

Ne jamais stocker les rôles dans une chaîne de caractères libre (text) sans validation stricte.


Exemple pratique

Créer la table des rôles

Créer le type ENUM et la table des rôles

Il est possible de créer le type ENUM et la table via le SQL Editor de Supabase.

  1. Ouvrir l’onglet SQL Editor.
  2. Exécuter la requête suivante pour créer le type ENUM :
create type user_role as enum ('guest', 'student', 'teacher', 'admin', 'super-admin');
  1. Créer ensuite la table user_roles :
create table public.user_roles (
id uuid default uuid_generate_v4() primary key,
user_id uuid references auth.users(id) not null,
role user_role not null default 'guest',
created_at timestamp with time zone default current_timestamp,
updated_at timestamp with time zone default current_timestamp
);

Insérer un rôle pour un utilisateur

Il est possible d’attribuer un rôle à un utilisateur existant :

insert into public.user_roles (user_id, role)
values ('<uuid_utilisateur>', 'admin');
remarque

Remplacer <uuid_utilisateur> par un identifiant réel d’utilisateur existant dans auth.users.


Vérifier le contenu de la table

Aller dans Table Editor > user_roles et vérifier que :

  • la ligne a bien été insérée,
  • le champ role est bien rempli,
  • les dates created_at et updated_at sont présentes.

Tester la sécurité du type ENUM

Tenter d’insérer une valeur non autorisée :

insert into public.user_roles (user_id, role)
values ('<uuid_utilisateur>', 'hacker');

Résultat attendu : une erreur indiquant que 'hacker' n’est pas une valeur valide pour user_role.


Test de mémorisation/compréhension


Quel est l'intérêt principal d'utiliser un type ENUM pour les rôles ?


Quel type de données est utilisé pour le champ 'role' dans la table user_roles ?


Quelle commande permet de créer un type ENUM dans PostgreSQL ?


Quelle est la valeur par défaut du champ 'role' dans la table user_roles ?


Que se passe-t-il si on insère une valeur non autorisée dans un champ ENUM ?


À quoi sert le champ updated_at dans la table user_roles ?


Quel est le type de données du champ id dans la table user_roles ?


Pourquoi faut-il auditer les changements de rôles ?


Quel champ dans user_roles référence un utilisateur ?


Quelle est la bonne pratique pour gérer les rôles dans une application sécurisée ?



TP pour réfléchir et résoudre des problèmes

1. Créer le type ENUM user_role

Dans l’éditeur SQL de Supabase, créer un type ENUM contenant les rôles suivants : 'guest', 'student', 'teacher', 'admin', 'super-admin'.

create type user_role as enum ('guest', 'student', 'teacher', 'admin', 'super-admin');
Une solution

2. Créer la table user_roles

Créer la table user_roles avec une référence à auth.users

Créer une table user_roles avec les colonnes suivantes :

  • id de type uuid, clé primaire, généré automatiquement
  • user_id de type uuid, référence à auth.users(id)
  • role de type user_role, avec la valeur par défaut 'guest'
  • created_at et updated_at de type timestamp with time zone, avec valeur par défaut à current_timestamp
Une solution

3. Insérer un rôle

Insérer un rôle pour un utilisateur existant

Insérer une ligne dans la table user_roles pour attribuer à un utilisateur existant le rôle 'admin'.

⚠️ Remplacer <uuid_utilisateur> par un identifiant réel d’un utilisateur de votre base Supabase.

Une solution

4. Vérifier que l’insertion a bien fonctionné

Vérifier que la ligne a bien été insérée dans la table user_roles :

  • Accéder à l’onglet Table Editor > user_roles
  • Vérifier que les colonnes user_id, role, created_at, updated_at sont correctement remplies
Une solution

5. Tester la sécurité du type ENUM

Tenter d’insérer une valeur non autorisée dans le champ role, comme 'hacker'.
Observer le comportement de PostgreSQL.

Une solution

6. Modifier le rôle d’un utilisateur existant

Mettre à jour le rôle d’un utilisateur en le passant de 'admin' à 'super-admin'.

Une solution

7. Un seul rôle par utilisateur

Ajouter une contrainte d’unicité sur user_id

Empêcher qu’un même utilisateur ait plusieurs rôles en ajoutant une contrainte UNIQUE(user_id).

Une solution

8. Vérifier les contraintes de sécurité

Essayer d’insérer un second rôle pour le même utilisateur.
Observer que la base de données empêche l’insertion.

Une solution

9. Lister tous les utilisateurs avec leur rôle

Créer une requête SQL qui affiche tous les utilisateurs et leur rôle (en joignant auth.users et user_roles).

Une solution

10. Retirer le rôle d’un utilisateur

Pour tester, supprimer un rôle attribué à un utilisateur.

Une solution