Exercice 1 : Forum - Service d'authentification   

Dans la classe LoginComponent, on peut utiliser directement la classe MessageService pour réaliser l’authentification de l’utilisateur mais ce n’est pas souhaitable car, si l’utilisateur accède directement à une autre page de votre application, cette page (ce composant) ne saura pas si l’utilisateur s’est bien authentifié ou non. Pour pallier ce problème, créez un nouveau service auth, qui conservera cette information dans un de ses attributs, appelons-le is_authenticated. Créez cet attribut. Par dependency injection, une instance de MessageService sera passée au constructeur de la classe AuthService. Dans le constructeur de ce dernier, affichez dans la console un message indiquant qu’une instance de AuthService vient d’être construite.

Rajoutez à votre classe AuthService une méthode sendAuthentication qui, étant donné une chaîne de caractères login et une chaîne password passées en paramètres, requête le script checkLogin.php du backend et renvoie un Observable sur la réponse du serveur (bien évidemment, vous utiliserez votre service MessageService pour effectuer cette requête).

Modifiez votre composant LoginComponent afin qu’il n’utilise plus MessageService mais AuthService. Testez bien que votre nouveau composant fonctionne correctement.

Les observables et le problème des multiples subscribers

On souhaite maintenant modifier le service auth de telle sorte que, quand le backend retourne sa réponse, on puisse mettre à jour l’attribut is_authenticated. Actuellement, votre méthode sendAuthentication doit directement retourner l’observable retourné par sendMessage, autrement dit votre code doit ressembler à :

auth.service.ts
sendAuthentication(login: string, password: string) : Observable<PhpData> {
  return this.message.sendMessage('checkLogin', {
     login: login,
     password: password
   });
}

Comme, pour mettre à jour is_authenticated, il faut attendre la réponse du backend, le plus simple serait de modifier le code ci-dessus de la manière suivante :

auth.service.ts
1sendAuthentication(login: string, password: string) : Observable<PhpData> {
2  const obs = this.message.sendMessage('checkLogin', {
3     login: login,
4     password: password
5   });
6  obs.subscribe(res => {this.is_authenticated = (res.status == 'ok');});
7  return obs;
8}

Malheureusement, un observable obs n’est censé avoir qu’un seul subscriber. Or, ici, sur la ligne 6 ci-dessus, on a un premier subscriber, et le LoginComponent est un deuxième subscriber puisqu’il doit savoir si le backend a authentifié l’utilisateur ou non avant de passer à la page des cours. Donc cette solution n’est pas terrible.

Une meilleure idée consisterait à créer vous-même un observable. Pour créer « manuellement » un observable, on peut utiliser une expression comme celle ci-dessous :

exemple.ts
// on crée un observable qui va transmettre un nombre entier
const obs = new Observable<number>((subscriber) => {
   // ici, on peut exécuter n'importe quel code qui permettra de calculer
   // la valeur de l'observable.....
   // quand on a à disposition les infos que l'observable doit transmettre,
   // on les transmet via la méthode next :
   subscriber.next(42); // on transmet le nombre 42
});

return obs;

Exercice 2 : Forum - Authentification et observables   

En vous basant sur le code ci-dessus, faites en sorte que :

  1. la méthode sendAuthentication mette à jour l’attribut is_authenticated quand la réponse du serveur arrive;

  2. la méthode sendAuthentication renvoie un observable qui contiendra la réponse du serveur (bien évidemment, on ne requêtera qu’une seule fois le backend).

Indice 1 

Rien n’empêche, à l’intérieur de la fonction (subscriber) => { … } d’appeler la méthode sendMessage() du MessageService.

Indice 2 

Dans la fonction (subscriber) => { … }, appelez la méthode sendMessage() du MessageService et souscrivez-y. Quand le backend vous a retourné sa réponse, exécutez l’instruction subscriber.next().

Solution :

Relisez bien l’indice 2, vous devriez être capable de faire ce code tout(e) seul(e).

Solution :

sendAuthentication(login: string, password: string) : Observable<PhpData> {
  const obs = new Observable<PhpData>((subscriber) => {
    this.message.sendMessage('checkLogin', {
      login: login,
      password: password
    }).subscribe((res: PhpData) => { // ici, on a reçu la réponse du backend
      this.is_authenticated = (res.status == 'ok');
      subscriber.next(res); // on transmet la réponse au LoginComponent
    });
  });

  // on retourne l'observable que l'on vient de créer auquel le
  // LoginComponent va souscrire
  return obs;
}

Exercice 3 : Forum - Garantir l'authentification pour accéder aux cours   

  1. Actuellement, vous ne pouvez empêcher un utilisateur d’accéder à la page de cours sans s’authentifier. Pour forcer cette authentification, créez une garde :

    ng generate guard auth
    

    et indiquez que vous souhaitez que cette garde implémente canActivateChild.

  2. Dans votre fichier app.routes.ts, faites en sorte que les routes cours et topics/:id soient enfants d’un path vide, comme le montre la section « Componentless Routes » tout en bas de la page située à l’url ci-dessous.

    https://angular.dev/api/router/Route#componentless-routes

    Ce path vide n’est associé à aucun composant, il sert juste à définir qui sont ses enfants, c’est-à-dire les composants impactés par la garde. La manière dont les routes des enfants fonctionnent est assez simple : imaginons que C est enfant de B qui, lui-même est enfant de A, alors la route pour atteindre C est :

    route_A/route_B/route_C
    

    Autrement dit, on concatène les routes avec des /. Si topics/:id est enfant du path vide, sa route sera donc /topics/:id.

    Testez votre forum. Il devrait fonctionner comme avant (et il n’est toujours pas protégé).

  3. Dans le fichier app.routes.ts, rajoutez la protection des enfants par la fonction authGuard de votre garde, comme le montrent les URLs ci-dessous :

    https://angular.dev/guide/routing/common-router-tasks#preventing-unauthorized-access

    https://angular.io/guide/router-tutorial-toh#canactivatechild-guarding-child-routes

    Éditez le fichier auth.guard.ts et faites en sorte que la fonction authGuard renvoie false au lieu de true. Maintenant, réessayez de vous logguer et de naviguer sur votre forum.

  4. Votre site est maintenant protégé, peut-être un peu trop vu que vous ne pouvez plus rien y faire. Pour finaliser votre protection, on veut faire en sorte que la garde renvoie true si vous êtes authentifié et false sinon. Pour cela, il suffit d’utiliser le service AuthService et son attribut is_authenticated. Malheureusement, votre garde n’est pas une classe et on ne peut donc pas passer AuthService par dependency injection dans son constructeur. L’URL ci-dessous vous montre comment faire en utilisant la fonction inject() :

    https://angular.dev/guide/di/dependency-injection#injecting-consuming-a-dependency

  5. Maintenant, lorsque votre garde devrait retourner un false, faites en sorte qu’elle fasse un navigateByUrl() vers la route /login. Cela permettra de rediriger l’utilisateur vers la page de login puisqu’il n’est pas encore authentifié.

Environnements

On va maintenant préparer le déploiement de votre application. C’est-à-dire qu’elle sera servie, non pas via un serveur ng serve local mais via votre serveur web Apache. Normalement, votre application est bien écrite et elle peut être déployée sans modification du code, à une exception près : votre service MessageService encode en « dur » l’URL du backend http://127.0.0.1/....., qui est une URL locale à votre machine et qui rendra donc le backend inaccessible de vos utilisateurs. Il faut donc la modifier quand on déploie l’application, ce qui n’est pas pratique, d’autant que le cycle de vie d’un logiciel est souvent constitué d’une alternance de développements/corrections de bugs et de déploiements.

Pour pallier ce problème, Angular propose la notion d’environnement. On crée un environnement via la commande suivante :

ng generate environments

Cela crée deux fichiers src/environments/environment.ts et src/environments/environment.development.ts. Le premier contient les variables d’environnement utilisées pour le déploiement tandis que le deuxième contient celles utilisées quand on exécute un ng serve. L’idée, pour exploiter ces deux fichiers est simple : ils sont constistués d’un objet environment qui contient exactement les mêmes propriétés, mais les valeurs de ces dernières sont adaptées suivant qu’on est en mode déploiement ou en mode développement en local. Quand on développe, on importe le fichier src/environments/environment.development.ts. Quand on déploie l’application, Angular modifie pour vous le nom de ce fichier et compile donc en important src/environments/environment.ts. Vous n’avez plus aucune modification à réaliser quand vous alternez développements et déploiements.

Exercice 4 : Forum - Backend et environnement   

Dans le fichier src/environments/environment.development.ts, créez une propriété backendPrefix qui contient le préfixe de l’URL du backend que vous aviez utilisé dans votre MessageService. Dans ce dernier, remplacez ce préfixe par backendPrefix.

Dans le fichier src/environments/environment.ts, créez également la propriété backendPrefix avec le préfixe permettant de joindre votre backend une fois que celui-ci sera déployé. Dans l’exercice suivant, on déploiera l’application (backend + frontend) dans un répertoire forum-angular-php du serveur Apache. Le préfixe devrait donc être quelque chose comme :

http://127.0.0.1/forum-angular-php/backend

En revanche, si vous installez votre application sur votre espace à la dirNum, le préfixe devrait être quelque chose comme :

https://votre_identifiant.pedaweb.univ-amu.fr/extranet/forum-angular-php/backend

Exercice 5 : Forum - Déploiement de votre application   

Actuellement, votre site est en développement (sur le port 4200 de localhost ou 127.0.0.1). Si vous souhaitez le déployer sur votre serveur Apache, vous devrez réaliser les opérations suivantes :

  1. tapez la commande :

    ng build --base-href /forum-angular-php/browser/
    

    Le dernier / est important, ne l’oubliez pas.

    Si vous obtenez un message vous indiquant que vous avez excédé le budget maximum, éditez le fichier angular.json, faites une recherche sur « budgets » et augmentez le budget mémoire alloué pour les warnings et les erreurs.

    Une fois que la commande fonctionne correctement, celle-ci compile votre application dans un sous-répertoire appelé dist/frontend/browser.

  2. Créez un répertoire forum-angular-php à la racine de votre serveur Apache et déplacez y le répertoire dist/frontend/browser créé par le ng build.

  3. Testez votre application. Elle est maintenant accessible via l’url :

    http://127.0.0.1/forum-angular-php/browser

    Si vous souhaitez qu’elle s’appelle autrement que browser, il vous faudra refaire le ng build en indiquant bien après le –base-href le chemin où se trouvera l’application sur votre serveur Apache.

  4. Regardez les fichiers qui ont été générés, ceux du répertoire forum-angular-php/browser. Vous pouvez voir qu’il y a très peu de fichiers. Angular a en effet compilé tous votre code source.

    Le build permet de produire une version optimisée de votre application. Vous pouvez d’ailleurs utiliser l’application lighthouse de Chrome ou l’onglet Performance de l’inspecteur de votre navigateur pour vérifier l’efficacité de votre application.

 
© C.G. 2007 - 2025