Comment mettre en place une application micro-frontend en Angular pour consommer l’API ?
Chaque semaine, retrouvez sur notre blog un article relatif à notre série « Guide pratique dédié à la sécurisation d’une application Java Spring Boot et son déploiement dans le Cloud AWS ». L’objectif est de réaliser, pas à pas, la configuration d’un environnement sécurisé, la création d’une API et in fine, son déploiement dans le cloud.
Introduction
Dans ce nouvel épisode, nous allons aborder la question des applications micro-frontends. Nous allons plus précisemment voir comment mettre en place une application micro-frontend en Angular pour consommer une API sécurisée.
Prérequis
Avant de plonger dans le code, assurez-vous d’avoir les bonnes versions des outils installés :
- Node.js : v18.17.1
- NPM : v10.4.0
- Angular CLI : 17.3.7
L’importance de la sécurité dans une architecture micro-frontend
Nous ne le dirons jamais assez, la sécurité est primordiale dans toute application. Et cela vaut doublement pour les architectures micro-frontend. En segmentant votre application en plusieurs parties indépendantes, vous devez vous assurer que chaque segment est sécurisé pour éviter des vulnérabilités potentielles. C’est pourquoi, utiliser OAuth2 et OpenID Connect avec Keycloak pour sécuriser vos API est une excellente façon de garantir que seules les demandes authentifiées et autorisées peuvent accéder à vos ressources.
Exposition d’une nouvelle API en Spring Boot
Suite à la création de notre projet Spring Boot dans l’épisode précédent, nous poursuivons aujourd’hui le développement en mettant en œuvre une nouvelle API. Cette API sera responsable de l’exposition d’une méthode de vérification d’autorisation via Keycloak. Elle utilisera la méthode de connexion pour générer et retourner un token, à condition que les identifiants fournis soient valides.
1. Création d’une nouvelle API Spring Boot
Nous entamerons le processus par la mise en place d’une nouvelle API Spring Boot. Cette API comprendra un contrôleur qui mettra à disposition deux points de terminaison : /auth/login et /auth/logout. Vous trouverez ci-dessous, les détails des classes requises pour cette configuration.
Gestion des requêtes d’authentification : AuthController.java
Le AuthController est conçu pour traiter de manière sécurisée les données sensibles des utilisateurs. Il garantit ainsi l’intégrité et la confidentialité des informations d’identification lors des processus de connexion et de déconnexion.
Fonctionnalités principales :
- Gestion de la connexion : le contrôleur expose un endpoint /auth/login qui accepte les requêtes POST contenant les identifiants de l’utilisateur, tels que le nom d’utilisateur et le mot de passe. Ces informations sont encapsulées dans un objet AuthRequest et transmises à la méthode login. Cette méthode vérifie d’abord l’existence des champs requis. Si les champs sont présents et valides, elle prépare et envoie une requête à Keycloak, un serveur d’identité qui gère l’authentification et la délivrance des tokens.
- Génération du token : en cas de succès de l’authentification par Keycloak, un token est généré et renvoyé dans un objet AuthResponse. Ce token est essentiel pour les sessions utilisateur et pour sécuriser l’accès aux autres parties de l’application nécessitant une authentification.
- Gestion des erreurs : en revanche, si les identifiants sont incorrects ou si Keycloak ne parvient pas à authentifier l’utilisateur, le contrôleur capture l’exception et renvoie une réponse appropriée. Cette dernière indique l’échec de l’authentification avec un message d’erreur détaillé.
- Déconnexion : le contrôleur offre également un endpoint /auth/logout qui permet aux utilisateurs de se déconnecter de l’application. Cette fonctionnalité est intéressante, notamment pour la gestion de la sécurité des sessions utilisateur.
Sécurité et bonnes pratiques :
- Validation des entrées : le contrôleur utilise des validations pour s’assurer que les données reçues via les requêtes sont valides avant de les traiter. Cela aide à prévenir les attaques telles que l’injection SQL et le cross-site scripting (XSS).
- Gestion sécurisée des exceptions : toutes les exceptions potentielles sont gérées de manière sécurisée pour éviter la divulgation d’informations sensibles sur l’infrastructure sous-jacente de l’application.
- Utilisation de HTTPS : il est recommandé que toutes les communications entre le client et le serveur soient sécurisées via HTTPS. Effectivement, cela assure que les données sensibles telles que les mots de passe et les tokens ne soient pas exposées à des écoutes indiscrètes.
Ce qu’il faut retenir ici est que AuthController.java est essentiel pour la sécurité de l’application Spring Boot. Il gère efficacement les processus d’authentification et de déconnexion tout en assurant la sécurité des données utilisateur
Définition des classes pour les requêtes et les réponses d’authentification, structurant les données échangées lors du processus de connexion :
2. Mise à jour de la configuration de Spring Security
Dans cette seconde section, nous nous concentrerons sur le fichier SecurityConfig.java, qui joue un rôle central dans la définition des règles de sécurité au niveau de l’application. Le fichier SecurityConfig.java est le cœur de la configuration de sécurité dans une application Spring Boot. Il étend la classe WebSecurityConfigurerAdapter et fournit un modèle pratique pour personnaliser à la fois l’authentification et l’autorisation dans l’application.
Renforcement de la sécurité
Pour aller plus loin et renforcer la sécurité de notre configuration, il est essentiel d’activer certaines fonctionnalités supplémentaires fournies par Spring Security :
- CSRF (Cross-Site Request Forgery) : Spring Security active la protection CSRF par défaut. Mais il est important de s’assurer que cette fonctionnalité est bien configurée, surtout si l’application expose des API REST.
- CORS (Cross-Origin Resource Sharing) : si l’application doit accepter des requêtes cross-origin, la configuration CORS doit être définie correctement pour éviter toute vulnérabilité.
- HTTPS : forcer l’utilisation de HTTPS au lieu de HTTP pour toutes les communications est crucial pour la sécurité des données en transit.
Endpoints publics et privés
Ce contrôleur gère les requêtes vers les endpoints publics et privés. Voyons dès à présent comment il contribue à la sécurité de l’application.
Gestion des endpoints publics et privés
- Endpoints publics :
Le HelloController expose un endpoint /api/public qui est accessible sans nécessiter d’authentification. Cela permet à n’importe quel utilisateur de récupérer des informations qui ne sont pas sensibles, telles que des informations générales ou des données non personnalisées. La méthode getPublic() dans le contrôleur renvoie simplement une réponse indiquant que le contenu est public. Cela peut être utilisé pour des démonstrations ou des tests de connectivité.
- Endpoints privés :
À l’inverse, l’endpoint /api/private est sécurisé et nécessite que l’utilisateur soit authentifié. Cela est géré par Spring Security, qui intercepte les requêtes vers cet endpoint et vérifie si l’utilisateur a les droits nécessaires pour y accéder. La méthode getPrivate() renvoie une réponse indiquant que le contenu est privé, ce qui est utile pour des données sensibles ou personnalisées que seuls les utilisateurs authentifiés devraient voir.
Contribution à la sécurité de l’application :
- Séparation claire des niveaux d’accès : en définissant clairement quels endpoints sont publics et lesquels sont privés, HelloController aide à prévenir les accès non autorisés aux données sensibles. Cela réduit notamment le risque de fuites de données et d’autres vulnérabilités de sécurité.
- Utilisation de Spring Security : le contrôleur tire parti des configurations de Spring Security pour appliquer des politiques d’accès. Par exemple, l’annotation @PreAuthorize pourrait être utilisée pour des vérifications d’autorisation plus fines sur les méthodes du contrôleur.
- Audit et logging : chaque méthode peut également être enrichie avec des fonctionnalités de logging. Cela permet de tracer les accès aux endpoints et de détecter des comportements anormaux ou des tentatives d’accès non autorisées.
Création de l’application micro-frontend en Angular
Maintenant que nous avons créé une nouvelle API Spring Boot, passons à la création de l’application micro-frontend en Angular. Cela implique plusieurs étapes clés, allant de la préparation de l’environnement de développement à l’intégration des services et des composants nécessaires pour une application fonctionnelle et sécurisée. Voici un développement approfondi de chaque étape mentionnée dans la section initiale.
1. Préparation de l’environnement de développement
Avant de commencer le développement, il est essentiel de s’assurer que tous les outils nécessaires sont installés et configurés correctement. Cela inclut Node.js, NPM et Angular CLI. Ces outils fournissent le socle nécessaire pour créer et gérer une application Angular.
- Installation de Node.js et NPM : ces outils permettent de gérer les packages nécessaires et d’exécuter l’environnement de développement local. La commande sudo apt install -y nodejs. npm permet d’installer ces outils sur des systèmes basés sur Debian/Ubuntu.
- Vérification des versions installées : il est crucial de vérifier ensuite que les versions installées de Node.js et NPM correspondent aux exigences du projet, afin d’éviter d’éventuels problèmes de compatibilité.
- Installation de Angular CLI : Angular CLI est un outil puissant pour initialiser, développer et maintenir des applications Angular. Il peut être installé globalement via NPM avec npm install -g @angular/cli@17.3.7.
Capture d’écran montrant les commandes pour installer Node.js et NPM, vérifier leurs versions et installer Angular CLI.
2. Installation des dépendances
Une fois l’environnement configuré, la prochaine étape consiste à installer les dépendances nécessaires pour le projet. Cela inclut les bibliothèques pour la gestion de l’état, les effets, et les interactions avec l’API backend.
- Installation de NgRx : NgRx est une bibliothèque de gestion d’état inspirée par Redux pour Angular. L’installation des packages NgRx tels que @ngrx/store, @ngrx/effects, @ngrx/entity, et @ngrx/store-devtools permet de gérer l’état de l’application de manière prévisible et performante.
- Installation de Bootstrap : Bootstrap est utilisé pour le stylisme rapide des composants de l’interface utilisateur, permettant une mise en page réactive et attrayante sans effort supplémentaire en CSS.
Créons maintenant nos services, composants, modules, et modèles de données. Voici les commandes à suivre :
Commandes pour la création d’une application Angular et l’installation des dépendances NgRx
3. Création des services, composants et modules
La structure de l’application est définie par ses composants, services, et modules. Chaque partie joue un rôle spécifique dans l’architecture de l’application, en effet :
- Services : les services tels que AuthService et AppService sont essentiels pour gérer la logique d’authentification et la communication avec l’API backend. Ils encapsulent la logique métier et assurent la réutilisabilité et la maintenance du code.
- Composants : les composants tels que NavbarComponent, LoginComponent et DisplayComponent définissent les éléments de l’interface utilisateur. Chaque composant est responsable de la gestion d’une partie spécifique de l’affichage et de l’interaction utilisateur.
- Modules : enfin, les modules Angular organisent le code en blocs fonctionnels distincts. Ils facilitent ainsi la charge paresseuse et l’isolation des différentes parties de l’application.
Commandes Angular CLI pour générer des services d’authentification, des composants de connexion, et des modules de routage.
4. Intégration des services AuthService et AppService
L’intégration des services est cruciale pour permettre aux composants de l’application de communiquer efficacement avec l’API backend et de gérer l’état de l’authentification.
- AuthService : ce service gère les requêtes d’authentification et la persistance du token d’utilisateur. Il joue un rôle central dans la sécurisation des routes et des données utilisateur.
- AppService : celui-ci récupère les données nécessaires depuis le backend, servant de pont entre l’API et les composants frontend.
En suivant ces étapes détaillées, le développement d’une application micro-frontend en Angular devient une tâche structurée et gérable. Ce qui permet de construire une application robuste et maintenable.
5. Création des composants de l’application
À ce stade, la création des composants implique la mise en place des éléments d’interface utilisateur qui interagiront avec les utilisateurs finaux. Penchons-nous davantage sur les détails de ses différentes étapes.
NavbarComponent
Le NavbarComponent fournit une barre de navigation pour l’application. Ce composant permet donc aux utilisateurs de naviguer facilement entre les différentes sections de l’application.
- navbar.component.html : ce fichier définit la structure HTML de la barre de navigation, incluant les liens vers les différentes parties de l’application.
DisplayComponents
Les DisplayComponents sont utilisés pour afficher le contenu public et privé de l’application. Ils servent à présenter les données de manière conditionnelle en fonction de l’état d’authentification de l’utilisateur.
- privateDisplay.component.ts et publicDisplay.component.ts : ces fichiers TypeScript définissent la logique pour afficher le contenu approprié aux utilisateurs authentifiés ou non. Les fichiers HTML associés définissent la structure du contenu à afficher pour chaque cas.
AuthentificationComponent et LoginComponent
Le LoginComponent est responsable de la gestion de l’authentification des utilisateurs. Ce composant fournit une interface permettant aux utilisateurs de se connecter à l’application.
- authlogin.component.html : ce fichier HTML crée le formulaire de connexion, incluant les champs pour le nom d’utilisateur et le mot de passe.
- login.component.ts : le fichier TypeScript associé gère la soumission du formulaire de connexion et communique avec le service d’authentification pour vérifier les identifiants de l’utilisateur.
6. Mise en place de NGRX pour la gestion de l’état
NGRX offre une solution robuste pour la gestion de l’état de l’application de manière prévisible. L’utilisation de NGRX implique la création de plusieurs fichiers pour configurer le store, les actions, les reducers et les selectors.
- auth.actions.ts, auth.effects.ts, auth.reducer.ts, auth.selectors.ts, myApp.state.ts : Ces fichiers constituent le cœur de la configuration de NGRX, permettant de gérer l’état d’authentification dans l’application.
7. Les modules
Les modules Angular sont des conteneurs dédiés à un ensemble cohérent de fonctionnalités d’une application. Ils permettent de structurer le code et de gérer les dépendances de manière efficace.
Module d’authentification
Le module AuthModule est responsable de toutes les fonctionnalités liées à l’authentification.
- CommonModule : fournit des directives et des services communs nécessaires pour les composants de ce module.
- AuthRoutingModule : contient les routes spécifiques à l’authentification.
- LoginComponent : composant responsable de l’affichage du formulaire de connexion.
- ReactiveFormsModule : utilisé pour créer et gérer des formulaires réactifs.
Module de l’interface privé
Le module PrivateModule gère les fonctionnalités privées accessibles uniquement aux utilisateurs authentifiés.
- DisplayComponent : composant utilisé pour afficher les données privées.
- KeycloakService : service utilisé pour l’authentification et l’autorisation via Keycloak.
- HttpClientModule : utilisé pour effectuer des requêtes HTTP.
8. La configuration des routes via les modules
La configuration des routes est essentielle pour naviguer entre les différentes vues de l’application Angular. Elle permet de définir quelles vues doivent être affichées pour chaque URL.
Module AuthRouting
Le module de routage AuthRoutingModule gère les routes pour les composants d’authentification.
- LoginComponent : définition de la route pour le composant de connexion. Cette route sera accessible via /auth/login.
Module PrivateRouting
Le module de routage PrivateRoutingModule gère les routes pour les composants privés.
- DisplayComponent : définition de la route pour le composant privé. Cette route sera accessible via /private.
Module PublicRouting
Le module de routage PublicRoutingModule gère quant à lui les routes pour les composants publics.
- DisplayComponent : définition de la route pour le composant public. Cette route sera accessible via /public.
Module AppRouting
Pour finir, le module de routage principal AppRoutingModule gère les routes globales de l’application.
- loadChildren : permet de charger les modules de manière asynchrone.
- redirectTo : redirige les utilisateurs vers la route /public par défaut.
9. Mise à jour de l’app.module
Le fichier app.module.ts agit comme le cœur de l’application Angular, orchestrant la coordination entre les différents modules, services, et composants. Voici les principales configurations réalisées dans ce fichier :
- Importation des modules nécessaires : tous les modules nécessaires pour l’application. Les modules Angular internes comme BrowserModule et HttpClientModule, ainsi que les modules personnalisés comme NavbarComponent et les modules de routage sont importés ici.
- Déclarations des composants : tous les composants utilisés dans l’application sont déclarés dans ce module. Cela inclut les composants pour la navigation, l’authentification, et l’affichage des données publiques et privées.
- Fournisseurs de services : les services tels que AuthService et AppService qui gèrent la logique d’authentification et la communication avec l’API backend, sont déclarés comme fournisseurs. Cela garantit qu’ils peuvent être injectés et utilisés dans n’importe quel composant de l’application.
- Intégration de NgRx : le StoreModule et EffectsModule de NgRx sont configurés pour gérer l’état global de l’application. Cela inclut la configuration des reducers et des effets, qui aident à gérer l’état de l’authentification et à traiter les effets secondaires comme les interactions avec l’API externe.
Test de l’application
Maintenant que notre application est configurée, il est temps de la tester. Dans cette nouvelle section, nous allons commencer par effectuer une installation propre des dépendances, puis démarrer l’application et vérifier les différents écrans via l’interface utilisateur.
1. Installation des dépendances
Tout d’abord, nous allons utiliser Maven pour effectuer une installation propre des dépendances. Assurez-vous d’être dans le répertoire racine de votre projet Spring Boot.
Commande Maven pour nettoyer le projet et installer les dépendances
Cette commande va nettoyer le projet, télécharger, installer toutes les dépendances nécessaires, et compiler le code.
2. Démarrage de l’application Angular
Ensuite, naviguez vers le répertoire de votre application Angular et démarrez le serveur de développement.
Commande pour démarrer le serveur de développement avec npm start
Cette commande va lancer le serveur de développement Angular et votre application sera disponible à l’adresse suivante : http://localhost:4200/
3. Test des écrans public et privé
Maintenant que l’application est en cours d’exécution, nous allons tester les différents écrans.
1. Écran Public :
- Accédez à l’URL http://localhost:4200/public.
- Vous devriez voir l’écran public s’afficher directement sans demander d’authentification.
Capture d’écran affichant l’interface utilisateur d’une application Angular en mode développement, avec un message confirmant le fonctionnement de l’affichage public
2. Écran privé :
- Accédez à l’URL http://localhost:4200/private.
- Si l’utilisateur est déjà authentifié, l’écran privé s’affiche directement.
- Sinon, vous serez redirigé vers l’écran de connexion.
Capture d’écran affichant l’interface de connexion
4. Authentification et accès à l’écran privé
Sur l’écran de connexion, suivez les étapes suivantes :
- Saisissez votre nom d’utilisateur et votre mot de passe.
- Cliquez sur le bouton de connexion.
Voici ce qu’il doit se passer ensuite :
- Le frontend envoie une requête au backend pour vérifier les informations d’identification.
- Le backend communique avec Keycloak pour générer un token basé sur les informations d’identification fournies et les autres paramètres Keycloak.
- Si les données de l’utilisateurs sont éronnées, il retourne un statut = KO qui signifie en back qu’il y a eu un 401 Unauthorized au frontend.
- Dans notre cas, nous avons envoyer :
– Username : my-user
– password = my-passwor. (éronné)
Capture d’écran montrant la section ‘Request Payload’ d’un outil de développement web, où des données d’authentification sont envoyées pour obtenir un token d’accès
Sur la console de chrome, nous voyons le retour de réponse :
Capture d’écran montrant une erreur HTTP 401 non autorisée lors d’une tentative de connexion à l’API locale, indiquant un problème d’authentification avec les détails de la requête et de la réponse.
Du côté du network, nous observons le 401 Unauthorized dans les headers :
Capture d’écran de l’inspecteur web montrant les détails d’une requête HTTP avec un code d’état 401 Unauthorized
La réponse retournée par le back est alors un Statut KO, comme nous pouvons l’observer dans la capture d’écran ci-dessous :
Capture d’écran de l’inspecteur web montrant les détails de la réponse en cas d’echec d’authorisation
À noter que, si le token est valide, il est retourné au frontend avec un statut « OK ».
Dans la capture d’écran ci-dessous, nous observons que le Statuts Code correspond à 200 OK, avec un statut ‘OK’. De plus, la réponse a renvoyé le token et le username au frontend.
Capture d’écran affichant l’interface utilisateur d’une application Angular en mode développement, avec un message confirmant le fonctionnement de l’affichage de la page privé suite à une authentification
Capture d’écran de l’inspecteur web montrant les détails de la réponse en cas d’authorisation avec succès
Pour finir, sur la capture d’écran ci-dessous, nous pouvons voir que :
- Le frontend stocke le token ainsi qu’une variable d’authentification isAuthentified dans le store NGRX. Il utilise également ce dernier pour accéder à l’endpoint /private du backend.
- Le token est passé dans l’en-tête de la requête HTTP au backend.
- Le backend vérifie le token et retourne le contenu de la page privée.
- Le frontend redirige ensuite l’utilisateur vers le contenu de la page privée et modifie le bouton login dans le navbar par le bouton logout.
Dans le code source vous pourrez trouver plus de détails, ainsi que l’implémentation du mécanisme de logout et des améliorations de sécurité pour l’authentification.
Conclusion
Pour conclure, récapitulons rapidement les points clés vus dans ce quatrième épisode. Nous avons détaillé :
- L’importance de la sécurité dans une architecture micro-frontend et comment OAuth2 et OpenID Connect avec Keycloak peuvent vous aider à sécuriser vos API.
- La préparation de l’environnement de développement en installant les versions nécessaires de Node.js, NPM, Angular CLI, et en utilisant IntelliJ IDE.
- La création d’une API Spring Boot sécurisée avec les endpoints /auth/login et /auth/logout et la configuration de Spring Security.
- Le développement d’une application micro-frontend en Angular avec les services AuthService et AppService, les composants Navbar, Private, Public, et Login, ainsi que l’intégration de NGRX pour la gestion de l’état.
- La création de modules et la configuration des routes pour organiser et naviguer efficacement dans l’application.
En suivant les différentes étapes détaillées ici, vous devriez avoir une architecture modulaire et sécurisée prête à être déployée.
Ressources complémentaires
Voici également quelques ressources supplémentaires pour approfondir vos connaissances :
Démo
Pour voir une démo complète de cette application, vous pouvez cloner les repo Github suivants :
Pour cloner le repository Git de l’application Frontend :