Création de l'authentification pour l'utilisateur - Créer un blog avec Adonis
Tags: webdev, adonisjs, tutorial, javascript
Published: 2021-08-21 10:11:15

Bonjour,

Bienvenue dans ce tutoriel pour apprendre à utiliser le [framework web Adonis](https://adonisjs.com/) ! Si tu souhaites en savoir plus sur Adonis en 1 coup œil, je t'invite à [lire cette page](https://adonisjs.com/adonisjs-at-a-glance).

Dans cette partie, on va voir le système de routing, de `controller` et un moyen pour authentifier l'utilisateur.

## Rappel

Ce tutoriel est la partie 3 d'une série de tutoriels qui ont pour objectif de te faire découvrir Adonis au travers la création d'un blog.

Pour lire la partie précédente, c'est là [Création d'un utilisateur - Créer un blog avec Adonis](https://dev.to/barbapapazes/creation-d-un-utilisateur-creer-un-blog-avec-adonis-1efi) 

Tu trouveras aussi sur GiHub l'ensemble du [code source du projet](https://github.com/Barbapapazes/create-a-blog-using-adonis) !

### Sommaire

Ce tutoriel est découpé en différente partie pour t'aider et pour éviter d'avoir des articles trop longs où l'on pourrait se perdre !

Nous allons donc voir ensemble :

- [Objectifs et mise en route - Créer un blog avec Adonis](https://dev.to/barbapapazes/objectifs-et-mise-en-route-creer-un-blog-avec-adonis-20lg)
- [Création d'un utilisateur - Créer un blog avec Adonis](https://dev.to/barbapapazes/creation-d-un-utilisateur-creer-un-blog-avec-adonis-1efi)
- [Création de l'authentification pour l'utilisateur - Créer un blog avec Adonis](https://dev.to/barbapapazes/creation-de-l-authentification-pour-l-utilisateur-creer-un-blog-avec-adonis-4mm8)
- [Création et visualisation des articles - Créer un blog avec Adonis](https://dev.to/barbapapazes/creation-et-visualisation-des-articles-creer-un-blog-avec-adonis-1d8k)
- [Gestion des articles - Créer un blog avec Adonis](https://dev.to/barbapapazes/gestion-des-articles-creer-un-blog-avec-adonis-2fc0)

Finalement, tu auras un blog fonctionnel !

## Création de l'authentification

Nous allons voir ensemble comment créer une route avec Adonis puis l'ajout d'un `controller` à cette dernière pour faciliter la gestion des fonctionnalités de notre application.

### Création d'une route

Pour commencer à créer des routes, rendons-nous dans le fichier `start/routes.ts`

Dans un premier temps, on va créer la route permettant d'afficher à l'utilisateur le formulaire pour s'authentifier puis dans un second temps, on fera la route qui permet d'authentifier l'utilisateur.

Dans notre fichier, on va commencer par créer la route `/login` et s'assurer que tout fonctionne.

```jsx
Route.get('login', () => {
  return 'Bienvenue sur la page de login'
})
```

Rends-toi à [cette adresse](http://localhost:3333/login) et tu vas voir ce message dans ton navigateur ! N'oublie pas de démarrer le serveur !

Super, mais comment on affiche de l'HTML à notre utilisateur ? Pour cela, on va utiliser le template engine edge. Nous allons donc créer une page puis demander au serveur de la générer puis de l'envoyer à l'utilisateur.

Commençons par créer la vue :

```jsx
node ace make:view login
```

Un nouveau fichier vient alors de faire son apparition dans `ressources/views`. Dans ce fichier, on va y créer un simple formulaire permettant à l'utilisateur de renseigner ses identifiants pour se connecter :

```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Login</title>
</head>
<body>
  <form action="/login" method="post">
    <div>
      <label for="pseudo">Votre pseudo</label>
      <input type="text" name="pseudo" id="pseudo">
    </div>
    <div>
      <label for="password">Votre password</label>
      <input type="text" name="password" id="password">
    </div>
    <button type="submit">Se connecter</button>
  </form>
</body>
</html>
```

L'action de ce formulaire nous indique que la requête sera sur `login` et la méthode nous indique `POST`. C'est donc comme cela que nous allons devoir définir nos routes !

Ensuite, nous allons indiquer à notre route de rendre cette page puis de la renvoyer à l'utilisateur. Changeons un peu notre code dans le fichier `start/routes.ts` :

```jsx
Route.get('login', ({ view }) => {
  return view.render('login')
})
```

Rends-toi à [cette adresse](http://localhost:3333/login) pour visualiser notre formulaire de connexion !

Pour en savoir plus : [Routing](https://docs.adonisjs.com/guides/routing), [Controllers](https://docs.adonisjs.com/guides/controllers), [Edge](https://docs.adonisjs.com/guides/views/introduction)

### Authentifier un utilisateur

#### Installation du module

Pour commencer à authentifier notre utilisateur, on va devoir installer et configurer un module : 

```bash
npm i @adonisjs/auth
```

Puis

```bash
node ace configure @adonisjs/auth
```

On indique que l'on souhaite utiliser Lucid pour trouver les utilisateurs. Ensuite, on va utiliser le web guard pour gérer l'authentification et enfin, on indique `User` comme modèle pour l'authentification. Puis on indique ne pas vouloir créer une migration comme cela a déjà été fait dans la partie précédente.

Dans le fichier `config/auth.ts`, il faut changer l'uids qui est à `email` par `pseudo`. En effet, dans la migration de notre utilisateur, nous avons indiqué que le pseudo devait être unique. Cela va permettre de le récupérer en base de données lors de l'authentification.

#### Authentification

Dans nos routes, nous allons créer une nouvelle route qui correspond à ce que l'on a mis dans le formulaire d'authentification.

```jsx
Route.post('login',async ({ request, auth, response }) => {
	return 'Post sur login'
})
```

Dans cette fonction, nous allons devoir récupérer de la requête le pseudo et le mot de passe provenant du formulaire. Puis, nous allons devoir authentifier l'utilisateur à l'aide de ses identifiants. Si les identifiants sont bons, alors on redirige l'utilisateur vers la page principale. Cependant, si les identifiants ne sont pas bons, alors on l'indique à l'utilisateur.

On récupère les entrées de l'utilisateur :

```jsx
const pseudo = request.input('pseudo')
const password = request.input('password')
```

Ensuite, nous essayons d'authentifier l'utilisateur. Dépendant du résultat, on redirige l'utilisateur sur `/` ou il est renvoyé sur la page `login` :

```jsx
try {
	await auth.attempt(pseudo, password)
	response.redirect('/')
} catch (error) {
	response.redirect().back()
}
```

Rends-toi à [cette adresse](http://localhost:3333/login) pour tester ! Pour rappel, notre unique utilisateur a pour pseudo `demo` et pour mot de passe `azerty` ! Tout se passe bien et tu es redirigé sur la page d'accueil. Cependant, si tu commets une erreur délibérée sur le mot de passe, alors rien ne te signale ce qui ne vas pas. Pas pratique !

Aussi, rien ne nous assure que les données entrées par l'utilisateur soient correctes. Ainsi, nous allons vérifier en amont ces données pour nous assurer de leur forme, type, format et intégrité.

Aussi, nous aimerions prévenir l'utilisateur des raisons qui peuvent faire qu'il n'arrive pas à s'authentifier ! Et pour cela, on va utiliser les sessions.

Et pour cela, nous allons utiliser un `Validator`.

#### Validation des entrées

Commençons par créer le validator :

```bash
node ace make:validator login
```

Ensuite, nous allons définir dans ce dernier la structure et le format des données que l'on souhaite avoir :

```jsx
public schema = schema.create({
  pseudo: schema.string({ trim: true }, [
    rules.exists({ table: 'users', column: 'pseudo' }),
  ]),
  password: schema.string(),
})
```

On indique que l'on souhaite une chaine de caractères nommée `pseudo` dont la valeur doit correspondre à une des entrées de la table `users` de la colonne `pseudo`. On indique que l'on souhaite une seconde chaine de caractères nommée `password`.

Parfait, essayons à nouveau de nous connecter mais en omettant le pseudo ! On n'est pas authentifié mais rien n'a vraiment changé sur la page pour l'utilisateur ! Et c'est normal ! Il faut maintenant indiquer à notre `controller` d'utiliser le `validator` :

```diff
- const pseudo = request.input('pseudo')
- const password = request.input('password')
---
+ import LoginValidator from 'App/Validators/LoginValidator'
//...
+ const { pseudo, password } = await request.validate(LoginValidator)
```

Ensuite, nous allons devoir donner à l'utilisateur des indications en fonction des erreurs qu'il commet !

#### Flash messages

Ce qui est pratique avec le `validator`, c'est qu'il gère pour nous les messages d'erreurs. Cependant, nous allons devoir les afficher dans la vue. Pour cela, ouvrons le fichier `login.edge` :

```diff
 <!DOCTYPE html>
 <html lang="en">
 <head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <meta http-equiv="X-UA-Compatible" content="ie=edge">
   <title>Login</title>
 </head>
 <body>
   <form action="/login" method="post">
     <div>
       <label for="pseudo">Votre pseudo</label>
+      <input type="text" name="pseudo" id="pseudo" value="{{ flashMessages.get('pseudo') ?? '' }}">
+      @if(flashMessages.has('errors.pseudo'))
+      <div>{{ flashMessages.get('errors.pseudo') }}</div>
+      @endif
     </div>
     <div>
       <label for="password">Votre password</label>
+      <input type="text" name="password" id="password" value="{{ flashMessages.get('password') ?? '' }}">
+      @if(flashMessages.has('errors.password'))
+      <div>{{ flashMessages.get('errors.password') }}</div>
+      @endif
     </div>
     <button type="submit">Se connecter</button>
   </form>
 </body>
 </html>
```

Comme on peut le voir, on ajoute à notre template une `div` qui contient le message contenu dans la session via `flashMessages`. Cependant, on ne souhaite faire cela que s'il y a un message à afficher, c'est pour cela qu'on entoure cette `div` de la condition de présence d'une erreur.

Aussi, on affecte à l'input sa précédente valeur. Cela permet de ne pas vider le formulaire en cas d'erreur de l'utilisateur lorsque nous le redirigeons via la méthode `back`.

Mais que faire en cas d'erreur dans l'authentification ? Pour cela, nous allons nous même enregistrer un message flash dans la fonction `store` du `controller` `login`.

```diff
 try {
   await auth.attempt(pseudo, password)
   response.redirect('/')
 } catch (error) {
+  session.flash('auth', 'Authentication impossible')
   response.redirect().back()
 }
```

On crée un nouveau message nommé "auth" qui contient "Authentification impossible". 

Pour que l'utilisateur soit en mesure de le voir, il nous faut faire comme dans le fichier `login.edge` :

```diff
 <button type="submit">Se connecter</button>
+@if(flashMessages.has('auth'))
+<div>{{ flashMessages.get('auth') }}</div>
+@endif
```

Rends-toi à [cette adresse](http://localhost:3333) pour essayer cela ! N'oublie pas de te tromper pour voir apparaitre les messages !

On remarque cependant que les messages du `validator` ne sont pas en français ! Pour les personnaliser, on peut se rendre dans le fichier `LoginValidator.ts` :

```jsx
public messages = {
  'pseudo.string': 'Le pseudo doit être une chaîne de caractères',
  'pseudo.required': 'Le pseudo est requis',
  'pseudo.exists': "Le pseudo n'existe pas",
  'password.string': 'Le mot de passe doit être une chaîne de caractères',
  'password.required': 'Le mot de passe est requis',
}
```

Les clés sont une correspondance avec la règle qui est appliquée et la vérification qui est effectuée. Retentons notre formulaire et voilà, les messages sont en français !

Pour en savoir plus : [Authentication](https://docs.adonisjs.com/guides/auth/introduction), [Web guard](https://docs.adonisjs.com/guides/auth/web-guard), [Validator](https://docs.adonisjs.com/guides/validator/introduction), [Flash](https://docs.adonisjs.com/guides/session#session-flash-messages), [Conditionals](https://docs.adonisjs.com/guides/views/conditionals)

### Création des `controllers`

Les fonctions qui se trouvent après le nom de nos routes dans le fichier `start/routes.ts` est en réalité des `controllers`. C'est à dire que ces fonctions vont gérer les requêtes des clients. Mais pour simplifier et faire que chaque fichier est son utilité, on préfère les extraire et les mettre dans un fichier à part.

Commençons par créer un `controller` :

```jsx
node ace make:controller login
```

Ensuite, nous allons devoir migrer nos 2 fonctions dans ce `controller` de la ressource `login`.

Pour ce faire, commençons par éditer le fichier `LoginController.ts`.

Dans une fonction nommée `create`, nous allons y mettre la gestion de la vue et dans une fonction nommée `store`, nous allons y mettre l'authentification de l'utilisateur. Le choix du nom de ces fonctions n'est pas au hasard et fait partie des conventions utilisées par Adonis, [plus de détails ici.](https://docs.adonisjs.com/guides/controllers#resourceful-routes-and-controllers)

```jsx
// Gestion de la vue pour l'utilisateur
public async create({ view }: HttpContextContract) {
  return view.render('login')
}

// Gestion de l'authentification
public async store({ request, auth, response, session }: HttpContextContract) {
  const { pseudo, password } = await request.validate(LoginValidator)

  try {
    await auth.use('web').attempt(pseudo, password)
    response.redirect('/articles')
  } catch (error) {
    session.flash('auth', 'Authentication impossible')
    response.redirect().back()
  }
}
```

Ensuite, nous allons indiquer simplement dans notre fichier de gestion des routes, quel est le `controller` qui gère la route. Pour cela, nous allons remplacer nos fonctions par une simple chaine de caractères.

```jsx
Route.get('login', 'LoginController.create')
Route.post('login', 'LoginController.store')
```

Cette chaine de caractères indique le nom du `controller` à utiliser `LoginController` et la fonction à exécuter, `create` dans le cas d'une requête de type `GET` et `store` dans le cas d'une requête `POST`.

Pour en savoir plus : [Controllers](https://docs.adonisjs.com/guides/controllers)

## Conclusion

Et voilà pour cette troisième partie. On a vu la création d'une route, de son `controller` associé. On a aussi abordé les notions de vue et d'authentification de l'utilisateur.

Dans la suite, on va commencer à modeler nos articles pour les visionner sur notre blog !

N'hésite pas à commenter si tu as des questions, si ça t'a plus ou même pour me faire des retours !

Et tu peux aussi me retrouver sur [Twitter](https://twitter.com/SOUBIRAN25) ou sur [LinkedIn](https://www.linkedin.com/in/esteban25/) !

On se donne rendez-vous ici, [Création et visualisation des articles - Créer un blog avec Adonis](https://dev.to/barbapapazes/creation-et-visualisation-des-articles-creer-un-blog-avec-adonis-1d8k) pour la suite du tutoriel et visualiser nos premier articles.