Introduction
Serverpod propose une multitude de fonctionnalités visant à simplifier le développement serveur :
- ORM (Object-Relational Mapping) : Serverpod permet de définir des modèles en Dart, utilisés ensuite pour générer automatiquement les structures SQLcorrespondantes.
- Génération des modèles SQL : En fonction des modèles définis, Serverpod génère le SQL nécessaire pour créer et gérer les tables dans la base de données.Opérations CRUD générées Toutes les opérations CRUD Insert, Find, Update, Delete) sont générées automatiquement, facilitant la gestion des données.
- Endpoints configurables : Les endpoints, permettant dʼinteragir avec la base de données, sont entièrement configurables en Dart en utilisant les opérationsCRUD générées, offrant une flexibilité maximale.
Dans cet article divisé en plusieurs parites, nous explorerons lʼimplémentation de Serverpod à travers un projet dʼexemple, en mettant en lumière ses forces etfaiblesses, notamment lʼauthentification, la définition du modèle de données, le développement des endpoints, et la liaison avec une application Flutter.
Lʼobjectif de se projet sera donc de créer une application où lʼutilisateur devra sʼidentifier afin de pouvoir de pouvoir interagir avec la base de données que nousaurons définis. Pour lʼexemple lʼapplication sera un registre de Jedi et Sith issus de Star Wars et sera nommée “Star Wars Podˮ.
L’authentification
Serverpod offre plusieurs possibilités pour l’implémentation de l’authentification au sein d’un projet :
- l’authentification email et mot de passe
- l’authentification avec Google
- l’authentification avec Apple
- l’authentification avec Firebase
Pour ce projet exemple nous implémenterons celle par email et mot de passe. Serverpod propose d’utiliser des widgets prédéfinis pour cette méthode d’authentification nommée SignInWithEmailButton(). Néanmoins, comme la plupart des applications intègrent leur propre design pour la partie d’authentification, nous coderons la version custom qui nous permettra également d’appréhender tous les aspects offerts Serverpod sur ce concept.
Pour démarrer, nous partons du principe que votre projet Serverpod est créé. Pour ce faire, vous pouvez suivre ce tutoriel.
1. Implémentation des dépendances
En ayant créé votre projet Serverpod, vous obtenez trois répertoires, un pour le client, un pour le serveur, et un autre pour notre application Flutter.
Il y a donc un fichier pubspec.yaml par répertoire, ajouter les dépendances comme suit :
Puis effectuez un flutter pub get sur chacun des répertoires.
2. Configuration côté Server
Ajoutez authenticationHandler à votre objet Serverpod comme suit :
Puis configurez votre objet AuthConfig avant le démarrage de votre serveur afin de gérer dans notre cas les validations de création de comptes et de réinitialisationde mots de passe :
Ces callbacks nous permettront de vérifier lʼemail de notre utilisateur avec un code de vérification qui leur sera envoyé sur leur boite mails lors dʼune création decompte ou dʼune réinitialisation de leur mot de passe. Afin de ne pas se compliquer la tâche ici, nous allons juste print() ces derniers. Pour ceux qui souhaitent allerplus loin, vous pouvez implémenter un envoi de mail en ajoutant et utilisant le package mailer sur votre serveur par exemple.
De plus, dans le fichier config/generator.yaml, ajoutez ceci :
Cette manipulation nous permet de renommer la module serverpod_auth que nous devrons importer plus tard dans notre modèle de données.
Maintenant que notre serveur et que les bonnes dépendances ont été correctement ajoutées dans les autres répertoires, effectuons les lignes de commandes suivantes à la racine de notre projet serveur :
- serverpod generate pour générer le SQL relatif à un compte utilisateur
- serverpod create-migration ou serverpod create-migration --force si une erreur se produit afin créer une migration de notre base de données avec les donnéesutilisateurs
- docker-compose up --build --detach pour démarrer notre docker Serverpod
- dart run bin/main.dart --role maintenance --apply-migrations afin de démarrer le notre serveur en appliquant notre migration précédente
Si vous parvenez à exécuter tout ceci avec succès cʼest que votre serveur est correctement configuré !
3. Configuration côté application Flutter
a. Interfaçage avec la base de données
Commençons par implémenter notre Client et notre SessionManager pour respectivement avoir accès à notre API (et plus particulièrement à nos endpoints que nous intègrerons dans la suite) et à lʼauthentification dans notre application.
Dans notre main.dart, ajoutons donc un singleton pour chacun de ces deux objets et initialisons tout ceci comme suit :
b. Création du widget dʼauthentification
Maintenant, développons une interface simpliste pour se connecter ou créer un compte, je le nomme AuthWidget :
c. Ajout des actions dʼauthentification
Dorénavant, afin dʼexécuter les méthodes dʼauthentification, nous allons avoir besoin dʼun objet EmailAuthcontroller à déclarer comme suit :
Ce controller nous donne accès à plusieurs fonctions, nous utiliserons donc les suivantes :
- _authController.createAccountRequest(userName, email, password)
- _authController.validateAccount(email, verificationCode)
- _authController.signIn(email, password)
Notre AuthWidget prendra donc en arguments de ces deux callbacks loginAction et createAccountAction, respectivement ces deux fonctions :
loginAction ne fait que mettre en place un loader durant le temps de réception de la réponse du signIn et rafraîchit la page en assignant _authenticatedUser .
createAccountAction met lui également en place un loader lors de lʼattente de la réponse de createAccountRequest , et si nous recevons un boolean à true, nous affichonsune dialog afin que lʼutilisateur vérifie son mail avec le code reçu (pour rappel, il sera simplement print par notre serveur dans cet exemple). Enfin, cette dialog jouerale validateAccount lors de la validation du code par lʼutilisateur avec un appui bouton. Pour une meilleure visualisation, le code de la dialog :
À ce stade, si à la racine de votre projet serveur vous démarrer votre Docker et votre serveur avec docker-compose up --build --detach et dart run bin/main.dart --apply-migrations vous devez être capable de créer un compte et de vous connecter comme sur cette démo.
Pour information, la page MyHomePage est développée comme suit :
d. Récupération de session
Nous pouvons également avec Serverpod récupérer la session du dernier utilisateur connecté. Pour ce faire, ajoutons ces éléments à MyHomePage :
Nous en avons aussi profité pour ajouter un listener sur notre SessionManager afin de nous éviter dʼeffectuer des setState() dès lors que lʼon souhaite mettre à jour notre _authenticatedUser (vous pouvez donc supprimer ceux déjà utilisés à cet effet dans le code) ce qui nous sera fortement utile pour la gestion de sa déconnexion.
Si vous inspectez le code derrière sessionManager.signInUser , vous remarquerez quʼune clé dʼauthentification est sauvegardée dans les shared preferences de lʼapplication. Lors dʼune déconnexion de lʼutilisateur, cette clé sera naturellement effacée.
e. Déconnexion de lʼutilisateur
Afin de réaliser la déconnexion, nous allons simplement ajouter un IconButton dans notre AppBar qui réalisera un sessionManager.signOut() :
Nous nous arrêterons ici pour ce projet en ce qui concerne lʼimplémentation de lʼauthentification. Si vous êtes intéressés par la réinitialisation du mot de passe, celaressemble énormément à la création de compte avec pour différence lʼutilisation des méthodes _authController.initiatePasswordReset(email) pour print le code devérification normalement envoyé par mail et _authController.resetPassword(email, verificationCode, password) pour définir le nouveau tout en spécifiant le code précédemment reçu. Vous pouvez également vous rendre sur cette partie de la documentation Serverpod si besoin.
4. Test des requêtes dʼauthentification avec Postman (bonus)
Afin de tester les fonctionnalités de notre serveur et notamment ici lʼauthentification sans avoir à exécuter notre application, nous utilisons régulièrement des outilscomme Postman. Néanmoins, cette utilisation nʼest pas poussée ni mise en avant par les développeurs de Serverpod comme le démontre ce ticket GitHub. Je nʼaiégalement à ce jour, rien trouvé à ce sujet dans la documentation du package. Néanmoins, cela ne veut pas dire que cʼest impossible ! En effet, après inspection ducode du package, jʼai pu déterminer comment tester tout ceci avec Postman.
Pour ce faire, il faut configurer la requête Postman comme suit (votre projet serveur doit bien évidemment être actif) :
Nous remarquons donc que nous sommes sur le endpoint http://localhost:8080/serverpod_auth.email , “serverpod_authˮ correspond au module que nous avons intégrédans notre pubsbec.yaml , et “emailˮ correspond au endpoint consacré à lʼauthentification par email. Nous spécifions aussi en paramètre du body de la requête laméthode “authenticate” ainsi que les arguments “email” et “password” .
De plus, nous recevons comme réponse, les userInfo (id, username, email...) et deux autres attributs : key et keyId . Ces derniers sont les informations stockées dansles shared préférences pour la récupération de la dernière session sous le format “$keyId:$key” . Souvenez-vous en car nous en aurons également besoin plus tardlors du développement de nos endpoints.
Nous pouvons aussi tester nos autres méthodes de la même manière en modifiant le body de notre requête pour une demande de création de compte et unevalidation :
Cela nous mêne donc à la fin de cette partie dʼauthentication avec Serverpod qui nous démontre une bonne maitrise de ce sujet par ce package avec uneimplémentation simple, efficiente et complète, notamment avec le déploiement possible des sign in with Google et Apple qui sont maintenant fortement répandusdans le monde du mobile en plus de lʼauthentification classique par mail.
Ainsi, nous continuerons lʼexploration de Serverpod avec la définition du modèle de données de notre application dans la prochaine partie de lʼarticle.
Quentin Lebreton - Ingénieur Études et Développement Junior