Ionic 2 partie 3 : L’authentification

    Dans cette troisième partie nous allons voir un exemple de mise en place d’une authentification au sein d’une application Ionic 2.  Comme pour les deux articles précédents nous allons prendre comme exemple notre application mobile NFC. Pour rappel, le premier article détaillait la structure du projet et le second article le menu et la navigation de l’application.

    Workflow

    Le processus d’authentification de notre application est très proche de celui évoqué dans notre article sur la sécurité HMAC puisqu’il s’agit ici aussi d’utiliser un Json Web Token.  Je ne vais pas redétailler le processus, je vous invite à relire l’article. L’idée, dans cette troisième partie, étant de voir comment stocker le JWT et comment l’envoyer automatiquement en header HTTP de chacune des requêtes de notre application Ionic 2.

    Mais commençons par le commencement et voyons tout d’abord la page de login.

    Page de login

    Dans nos sources, on peut retrouver les différentes classes et templates liés au login dans le dossier app/pages/login

    Template

    Le formulaire de login se trouve dans le fichier login.html et son contenu est relativement classique:

    • Notre formulaire contient trois champs: username, password et rememberMe et bien entendu on retrouve sur chacun d’entre eux la directive  [(ngModel)]  pour le binding bidirectionnel.
    • La validation du formulaire est possible grâce aux directives [ngFormModel]  et   ngControl  (sera détaillé dans le chapitre suivant).
    • A la soumission du formulaire la fonction login est appelée grâce à la directive  (submit)  sur le tag form .

    Composant

    Voyons maintenant le composant @Page  associé au formulaire et qui est déclaré dans le fichier login.ts :

    •  L’attribut templateUrl  nous permet de faire le lien avec notre fichier de template et  providers crée un injecteur pour le service LoginService, déclaré dans la fichier login.service.ts, ce qui nous permettra de faire une injection de dépendance comme c’est le cas dans le constructeur. 
    • Deux variables sont créées sur la classe :
      • loginForm: Du type ControlGroup qui va nous permettre de faire la validation (voir plus bas).
      • rememberMe:  Liée à la checkbox du template par la directive ngModel et est initialisée à false. La case sera donc décochée par défaut.
    • On retrouve notre fonction login  appelée par l’événement (submit)  du formulaire.  Comme on peut s’en douter la fonction login  fait appel au service LoginService  et notamment à sa méthode doLogin qui va se charger de l’authentification à proprement parler.  
    • La méthode this.loginService.login retourne un Observable, ainsi :
      • En cas de succès de l’authentification, on redirige l’utilisateur vers la page d’accueil : NfcPage 
      • En cas d’échec on reste sur la page de login et on affiche une alerte d’erreur.
      • this.nav  est une instance de NavController (Voir l’article sur la navigation au sein d’ionic 2

    Service login

    Authentification

     Comme on peut s’y attendre, le service fait une injection de dépendance sur Http ce qui nous permettra de faire un appel au backend. L’url de login appelée est un mock créé sur la plateforme mockable.io et qui permet de retourner des données et des headers http statiques.

    Tout se passe dans la méthode login du service qui prend en paramètre les identifiants, le « remember me » et qui retourne un Observable:

    Dans un premier temps on vérifie, de manière statique, si les identifiants saisis sont corrects. Si ils ne le sont pas, une modal d’erreur est affichée et une exception est levée via la méthode Observable.throw.

    Si les informations saisies sont correctes, une requête http de type POST est faîte grâce au service http d’Angular 2 dont toutes les méthodes retourne un Observable .

    Json Web Token

    Structure

    Mais la partie qui nous intéresse vraiment est la récupération des données renvoyées par le webservice d’authentification et notamment le JWT dont voici la donnée brute :

    {"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiIxIiwiaWF0IjoxN DU4NzM1Njc5LCJleHAiOjE0NTg3MzcxMTQsImF1ZCI6Ind3dy5yZWRmcm9nZ3kuZnIiLCJzdW IiOiJtaWNoYWVsLmRlc2lnYXVkQHJlZGZyb2dneS5mciIsImZpcnN0TmFtZSI6Ik1pY2hhZWw iLCJsYXN0TmFtZSI6IkRlc2lnYXVkIiwicm9sZSI6WyJNYW5hZ2VyIiwiVXNlciJdfQ.ZAeN- thKID2PMEvjT9nwRRf5gsHlwCuKQEOCZIMBv-Q"} 

    Il s’agit d’un objet au format JSON avec une seule propriété « token » ayant pour valeur un jwt.

    Pour rappel un jwt est constitué de trois parties. Chacune est encodée en base64 et c’est la deuxième qui nous intéresse. On appelle le « payload » et la donnée décodée contient :

    On retrouve principalement des données utilisateurs et c’est ce que l’on cherche à récupérer et à stocker localement en plus du jwt lui même.

    Récupération et stockage

    On parse tout d’abord la réponse en objet json puis on récupère le token :

    La méthode readJwt de la classe LoginService va lire les données du payload qui sont ensuite affectées à une instance de la classe User. Le token JWT est ensuite stocké en local storage via la classe utilitaire StorageUtils et sera utilisé pour toute les futures requêtes http dans le header Authorization .

    Si l’utilisateur a coché la case rememberMe on stocke les informations de l’utilisateur et le jwt en local storage.  On pourrait évidemment ne stocker que le jwt étant donnée que la variable user est instanciée à partir de données extraites du payload jwt mais pour des raisons pratiques et pour ne pas avoir à extraire ces informations systématiquement on les stocke également.

    Ces données seront notamment affichées dans la page « Mon compte« .

    Lancement de l’application

    Ce que l’on souhaite c’est qu’au lancement de l’application la page de login soit affichée si l’utilisateur ne s’est jamais connecté ou s’il n’a pas coché la case « se souvenir de moi ». Dans le cas contraire on ne présente pas l’écran d’authentification et on affiche directement la page d’accueil.

    C’est naturellement dans le fichier app.ts (qui est notre point d’entrée) que cela va se jouer :

    Rien de tres compliqué ici, on teste simplement la présence des données utilisateurs en local storage. Il nous reste désormais à voir comment envoyer le jwt dans chaque requête http via notamment le header Authorization .

    Surcharge HTTP

    En effet une authentification par token nécessite que le client envoi systématiquement le jeton afin qu’il puisse s’identifier auprès du serveur. Coté Ionic 2 /Angular 2 l’astuce est de surcharger la classe http offerte par le Framework Angular pour notamment ajouter globalement notre jeton dans un header http comme nous l’avions expliquer dans notre article sur Angular2, Spring et HMAC.

    La classe JwtHttp répond à ce besoin et ajoute le header « Authorization » pour chacune des différents type de requêtes : get, post, put delete, etc..

    Malheureusement pour que Angular utilise notre classe cela ne suffit pas. Il nous faut créer la factory correspondante sur l’annotation @App  dans le fichier app.ts :

    Ainsi à chaque injection de dépendance sur la classe http, l’instance de JwtHttp créée dans la fonction useFactory sera utilisée.

     

    Nous verrons dans notre prochain article un exemple d’utilisation d’un plugin cordova.