Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Semaine 2

Le lien du Discord est : https://discord.gg/KERTwSz63

Lors de cette séance, nous allons ajouter une base de données (BDD) à notre service pour stocker les utilisateurs, puis hacher leurs mots de passe. Le contrôleur User utilisera ensuite la BDD et proposera de nouvelles routes.

Changements à apporter au code de la semaine 1

Conservez les modèles User, UserPass, UserPublic et l’énumération UserRole de la semaine 1.

En revanche, la liste static _users et le compteur _nextId disparaissent : la BDD stocke désormais les utilisateurs et leur attribue les identifiants.

Base de données

Lisez le chapitre Base de données, puis :

  1. Installez les paquets EF Core et l’outil dotnet ef : voir Installation des dépendances.
  2. Créez une classe BDDContext dans le dossier Models, avec une propriété DbSet<User> Users : voir Définir notre connexion à une BDD. La table s’appellera Users.
  3. Configurez SQLite avec le fichier BDD.db (Configurer SQLite), puis enregistrez le contexte dans Program.cs (Initialiser la BDD au lancement).
  4. Créez la migration initiale, puis appliquez-la : voir Les migrations et Création de la BDD.

L’enregistrement du contexte dans Program.cs ne crée pas la table : tant que la migration n’est pas appliquée, les requêtes échouent.

Hacher les mots de passe

Les mots de passe ne doivent jamais être stockés en clair. Lisez le chapitre Password Hasher, puis :

  • Enregistrez un PasswordHasher<User> dans Program.cs : voir Injecter le hasher.
  • Register : hachez le mot de passe avant d’enregistrer l’utilisateur.
  • Login : recherchez d’abord l’utilisateur par son Username, puis vérifiez le mot de passe reçu avec VerifyHashedPassword : voir Vérifier un mot de passe. Ne comparez jamais le mot de passe reçu au champ Password, et ne cherchez pas un utilisateur à partir de son mot de passe.
  • PUT : si un nouveau mot de passe est fourni, hachez-le avant l’enregistrement. S’il est absent ou vide, conservez le mot de passe actuel.

Si vous avez enregistré des utilisateurs avant de hacher leurs mots de passe, supprimez-les : ils ne pourront plus se connecter.

Ne renvoyez jamais le mot de passe, haché ou en clair, dans les réponses de votre service : renvoyez toujours un UserPublic.

Utiliser la BDD dans le contrôleur

Injectez BDDContext et PasswordHasher<User> dans le constructeur de UserController : voir Injection de dépendance et Utiliser la BDD dans un contrôleur. Réécrivez ensuite les actions pour qu’elles utilisent la BDD ; elles deviennent asynchrones (voir Async).

Chapitres utiles pour chaque opération :

Vous pouvez ajouter la contrainte :int aux paramètres {id} de vos routes : voir Annotations.

Routes attendues

RouteEntréeComportementRéponse HTTP
GET /api/User/{id}Identifiant dans l’URLRenvoie l’utilisateur correspondant.200 + UserPublic, ou 404
POST /api/User/RegisterCorps JSON UserPassCrée un utilisateur avec le rôle User et un mot de passe haché.200 + UserPublic
POST /api/User/LoginCorps JSON UserPassVérifie le pseudo et le mot de passe.200 + UserPublic ; 404 si le pseudo est inconnu ; 401 si le mot de passe est incorrect
PUT /api/User/{id}Identifiant dans l’URL et corps JSON UserUpdateModifie le pseudo, le rôle et, s’il est fourni, le mot de passe.200 + UserPublic, ou 404
DELETE /api/User/{id}Identifiant dans l’URLSupprime l’utilisateur.200 + true, ou 404
GET /api/User/AllAucuneRenvoie tous les utilisateurs.200 + liste de UserPublic
GET /api/User/AllAdminAucuneRenvoie les utilisateurs dont le rôle est Admin.200 + liste de UserPublic
GET /api/User/Search/{name}Fragment de pseudo dans l’URLRenvoie les utilisateurs dont le Username contient name, en respectant les majuscules et minuscules.200 + liste de UserPublic

Une liste sans résultat est renvoyée sous la forme [].

UserUpdate est une nouvelle classe, indépendante de UserPass, avec trois propriétés : Username, Password et Role (de type UserRole). Déclarez Password en string? pour qu’il puisse être omis.

L’unicité des pseudos sera traitée en semaine 3.

À ce stade, aucune route ne vérifie l'identité de l'appelant : n'importe qui peut modifier le rôle d'un utilisateur ou supprimer un compte. Gardez l'API en local et n'utilisez que des comptes fictifs. Ces routes seront réservées aux administrateurs en semaine 5.

Vérification finale et livrables

Relancez l’API, ouvrez Scalar et vérifiez que les huit routes apparaissent. Réalisez ensuite le scénario suivant :

  1. Inscrivez Alice puis Bob avec Register : vérifiez le code 200, l’identifiant attribué, le rôle 1 et l’absence de mot de passe dans la réponse.
  2. Ouvrez BDD.db, par exemple avec l’extension SQLite Viewer citée dans le Setup : la colonne Password doit contenir un hash, et non le mot de passe saisi.
  3. Redémarrez l’application, puis appelez All : Alice et Bob doivent toujours apparaître.
  4. Appelez Login pour Alice avec le bon mot de passe (200), avec un mauvais mot de passe (401), puis avec un pseudo inexistant (404).
  5. Avec PUT, donnez le rôle 0 (Admin) à Alice en conservant son pseudo et sans fournir de mot de passe : Alice doit apparaître dans AllAdmin et se connecter avec son ancien mot de passe.
  6. Avec PUT, changez le mot de passe de Bob : l’ancien mot de passe doit renvoyer 401, le nouveau 200.
  7. Appelez Search avec Ali : seule Alice doit apparaître. Avec ali, la liste doit être vide.
  8. Supprimez Bob avec DELETE (200 et true), puis demandez-le avec GET /api/User/{id} : vous devez recevoir 404.

À la fin de la séance, vous devez avoir :

  • Les modèles User, UserPass, UserPublic, UserUpdate et l’énumération UserRole (Admin = 0, User = 1).
  • Un BDDContext enregistré dans Program.cs, une migration initiale appliquée et un fichier BDD.db contenant la table Users.
  • Les huit routes de UserController reposant sur la BDD, sans liste static.
  • Des mots de passe hachés en base, et aucun mot de passe dans les réponses.