📐 Construire une app en JS
09 Authentification

Authentification

Dans notre use-case de réservation, on indique par le paramètre tenantId l'identifiant du vacancier à l'origine de la demande.

book({
    tenantId:"faketenant@mail.com", 
    accomodationId:"accomodation-1", 
    adults:2, children:3, 
    from : new Date("2024-06-02"),
    to :   new Date("2024-06-02"),
    })

C'est en général une mauvaise pratique de préciser qui est à l'orgine de la demande.

Pourquoi ?

Parce que c'est une faille possible de sécurité. Cela sous-entend qu'un vacancier pourrait réaliser une réservation au nom d'un autre vacancier.

Bine-sûr, on peut se prémunir de cette possibilité dans le code du use-case. Mais on lieux vaut intégrer la sécurité à la racine. On souhaite de la sécurité par conception (security by design).

Modifions notre test pour ne plus passer de tenantId dans la commande book().

Enchaîner les use-cases

Concrêtement, notre vacancier entre son login et son mot de passe sur notre site. Puis il recherche un logement. Puis il effectue une réservation.

Voilà le parcours utilisateur. L'histoire que l'on veut raconter au travers de notre code.

Simplifions-là en considérant que l'utilisateur sait exactement quel hébergement il veut réserver.

Avant de réserver, l'utilisateur passe par une authentification. Racontons cette histoire dans notre test.

// Injection des dépendances
const app = new App(testDependencies())
 
// Réalisation de la location
await app.run([
    login({email:"faketenant@mail.com", password:"secret"}),
    book({
        // tenantId:"faketenant@mail.com", <- supprimons ça 
        accomodationId:"accomodation-1", 
        adults:2, children:3, 
        from : new Date("2024-06-02"),
        to :   new Date("2024-06-02"),
        })
]);
 
// Le calendrier comporte la réservation
const bookings = await app.dependencies.listBookingsForAccomodationId("accomodation-1")
expect(bookings).toHaveLength(1)

Oberservez le changement de notre méthode App.run().

Elle prend en paramètres une liste de commandes, et non plus une seule commande. Ainsi notre test raconte explicitement l'histoire du parcours de l'utilisateur :

  • d'abord s'authentifier, avec un email et un mot de passe
  • puis faire la réservation

Ce qui conduit à une nouvelle commande login()

Le contexte

D'abord, login() est-elle vraiment une commande ?

Rappelons-nous la définition : une commande change l'état du système.

Clairement, c'est le cas. Invoquer login() conduit à modifier l'état du système pour ajouter l'utilisateur connecté (si les login/mot de passe sont OK). Dit autrement, l'état du système ne peut pas être le même si 2 utilisateurs différents sont connectés.

Mais ne perdons pas de vue l'objectif initial : ne plus passer de tenantId dans la commande book().

Les informations de connexion déterminées par la commande login() doivent dont être passés à la commande book() qui a besoin de savoir qui est l'utilisateur à l'origine de la demande de réservation.

Nous allons donc créer un contexte d'exécution. Ce contexte sera passé de commandes en commandes.

Le contexte sera :

  • vide au départ
  • éventuellement rempli avec l'utilisateur authentifié par une commande login()
  • éventuellement assorti d'une erreur pour éviter continuer à dérouler les commandes suivantes après l'échec d'une commande.

Ce contexte est une monade. Mais laissons de côté ce terme pour commencer à coder notre application à partir de notre test.

Enfin !