Spring Cloud - Ajout de 4 angulaires

Spring Cloud - Ajout de 4 angulaires

1. Vue d'ensemble

Dans notre dernier article Spring Cloud, nous avons ajouté la prise en charge deZipkin dans notre application. Dans cet article, nous allons ajouter une application frontale à notre pile.

Jusqu'à présent, nous avons travaillé entièrement sur le back-end pour créer notre application cloud. Mais à quoi sert une application Web s'il n'y a pas d'interface utilisateur? Dans cet article, nous allons résoudre ce problème en intégrant une application d'une seule page dans notre projet.

Nous allons écrire cette application en utilisantAngular etBootstrap. Le style de code Angular 4 ressemble beaucoup à celui d'une application Spring, qui est un croisement naturel pour un développeur Spring! Bien que le code frontal utilise Angular, le contenu de cet article peut facilement être étendu à n’importe quel framework frontal avec un minimum d’effort.

Dans cet article, nous allons créer une application Angular 4 et la connecter à nos services cloud. Nous montrerons comment intégrer la connexion entre un SPA et Spring Security. Nous montrerons également comment accéder aux données de notre application à l'aide de la prise en charge d'Angular pour la communication HTTP.

2. Modifications de la passerelle

Avec le frontal en place, nous allons passer à la connexion par formulaire et sécuriser les parties de l'interface utilisateur aux utilisateurs privilégiés. Cela nécessite d’apporter des modifications à la configuration de sécurité de notre passerelle.

2.1. Mettre à jourHttpSecurity

Tout d'abord, mettons à jour la méthodeconfigure(HttpSecurity http) dans notre classe de passerelleSecurityConfig.java:

@Override
protected void configure(HttpSecurity http) {
    http
      .formLogin()
      .defaultSuccessUrl("/home/index.html", true)
      .and()
    .authorizeRequests()
      .antMatchers("/book-service/**", "/rating-service/**", "/login*", "/")
      .permitAll()
      .antMatchers("/eureka/**").hasRole("ADMIN")
      .anyRequest().authenticated()
      .and()
    .logout()
      .and()
    .csrf().disable();
}

Tout d'abord, nous ajoutons une URL de réussite par défaut pour pointer vers/home/index.html car c'est là que réside notre application Angular. Ensuite, nous configurons les correspondants fourmi pour autoriser toute demande via la passerelle à l'exception des ressourcesEureka. Cela déléguera tous les contrôles de sécurité aux services d'arrière-plan.

Ensuite, nous avons supprimé l'URL de réussite de la déconnexion, car la redirection par défaut vers la page de connexion fonctionnera correctement.

2.2. Ajouter un point de terminaison principal

Ensuite, ajoutons un point de terminaison pour renvoyer l'utilisateur authentifié. Cela sera utilisé dans notre application angulaire pour vous connecter et identifier les rôles de notre utilisateur. Cela nous aidera à contrôler les actions qu’ils peuvent effectuer sur notre site.

Dans le projet de passerelle, ajoutez une classeAuthenticationController:

@RestController
public class AuthenticationController {

    @GetMapping("/me")
    public Principal getMyUser(Principal principal) {
        return principal;
    }
}

Le contrôleur renvoie l'objet utilisateur actuellement connecté à l'appelant. Cela nous donne toutes les informations dont nous avons besoin pour contrôler notre application Angular.

2.3. Ajouter une page de destination

Ajoutons une page de destination très simple pour que les utilisateurs voient quelque chose lorsqu'ils accèdent à la racine de notre application.

Danssrc/main/resources/static, ajoutons un fichierindex.html avec un lien vers la page de connexion:




    
    Book Rater Landing


    

Book Rater

So many great things about the books

Login

3. CLI angulaire et le projet de démarrage

Avant de démarrer un nouveau projet Angular, assurez-vous d'installer les dernières versions deNode.js and npm.

3.1. Installez la CLI angulaire

Pour commencer, nous devrons utilisernpm pour télécharger et installer l'interface de ligne de commande Angular. Ouvrez un terminal et lancez:

npm install -g @angular/cli

Cela téléchargera et installera la CLI globalement.

3.2. Installer un nouveau projet

Toujours dans le terminal, accédez au projet de passerelle et allez dans le dossier gateway / src / main. Créez un répertoire appelé «angular» et accédez à celui-ci. De là courir:

ng new ui

Sois patient; la CLI met en place un tout nouveau projet et télécharge toutes les dépendances JavaScript avec npm. Il n’est pas rare que ce processus prenne plusieurs minutes.

La commandeng est le raccourci de la CLI angulaire, le paramètrenew indique à la CLI de créer un nouveau projet et la commandeui donne un nom à notre projet.

3.3. Exécutez le projet

Une fois la commandenew terminée. Accédez au dossierui qui a été créé et exécuté:

ng serve

Une fois le projet construit, accédez àhttp://localhost:4200. Nous devrions voir cela dans le navigateur:

image

Toutes nos félicitations! Nous venons de construire une application angulaire!

3.4. Installer Bootstrap

Utilisons npm pour installer bootstrap. Depuis le répertoire ui, exécutez cette commande:

npm install [email protected] --save

Cela téléchargera bootstrap dans le dossier node_modules.

Dans le répertoireui, ouvrez le fichier.angular-cli.json. C'est le fichier qui configure certaines propriétés de notre projet. Trouvez la propriétéapps > styles et ajoutez un emplacement de fichier de notre classe CSS Bootstrap:

"styles": [
    "styles.css",
    "../node_modules/bootstrap/dist/css/bootstrap.min.css"
],

Cela demandera à Angular d'inclure Bootstrap dans le fichier CSS compilé qui est construit avec le projet.

3.5. Définir le répertoire de sortie de la construction

Ensuite, nous devons dire à Angular où placer les fichiers de construction afin que notre application de démarrage printanier puisse les servir. Spring Boot peut servir des fichiers à partir de deux emplacements dans le dossier des ressources:

  • src/main/resources/static

  • src/main/resource/public

Étant donné que nous utilisons déjà le dossier statique pour diffuser certaines ressources pour Eureka et qu'Angular supprime ce dossier chaque fois qu'une compilation est exécutée, créons notre application Angular dans le dossier public.

Ouvrez à nouveau le fichier.angular-cli.json et recherchez la propriétéapps > outDir. Mettre à jour cestring:

"outDir": "../../resources/static/home",

Si le projet Angular est situé dans src / main / angular / ui, alors il sera construit dans le dossier src / main / resources / public. Si l'application se trouve dans un autre dossier, cette chaîne devra être modifiée pour définir l'emplacement correctement.

3.6. Automatisez la construction avec Maven

Enfin, nous allons configurer un build automatisé à exécuter lors de la compilation de notre code. Cette tâche ant exécutera la tâche de construction de la CLI angulaire à chaque exécution de «mvn compile». Ajoutez cette étape au POM.xml de la passerelle pour vous assurer que chaque fois que nous compilons nous obtenons les dernières modifications de l'interface utilisateur:


    maven-antrun-plugin
    
        
            generate-resources
            
                
                    
                        
                        
                        
                    
                    
                        
                        
                    
                
            
            
                run
            
        
    

Nous devons noter que cette configuration nécessite que la CLI angulaire soit disponible sur le classpath. Transférer ce script dans un environnement dépourvu de cette dépendance entraînera des échecs de génération.

Commençons maintenant à créer notre application Angular!

4. Angulaire

Dans cette section du didacticiel, nous construisons un mécanisme d'authentification dans notre page. Nous utilisons l'authentification de base et suivons un simple flux pour que cela fonctionne.

Les utilisateurs ont un formulaire de connexion où ils peuvent entrer leur nom d'utilisateur et leur mot de passe.

Ensuite, nous utilisons leurs informations d'identification pour créer un jeton d'authentification base64 et demander le point de terminaison“/me”. Le point de terminaison renvoie un objetPrincipal contenant les rôles de cet utilisateur.

Enfin, nous allons stocker les informations d'identification et le principal sur le client à utiliser dans les demandes ultérieures.

Voyons comment cela se fait!

4.1. Modèle

Dans le projet de passerelle, accédez àsrc/main/angular/ui/src/app et ouvrez le fichierapp.component.html. Il s’agit du premier modèle chargé par Angular et sera l’endroit où nos utilisateurs atterriront après la connexion.

Ici, nous allons ajouter du code pour afficher une barre de navigation avec un formulaire de connexion:



Book Rater App

Anyone can view the books.

Users can view and create ratings

Admins can do anything!

Ce code configure une barre de navigation avec les classes Bootstrap. Un formulaire de connexion en ligne est intégré à la barre. Angular utilise ce balisage pour interagir de manière dynamique avec JavaScript afin de restituer diverses parties de la page et de contrôler des éléments tels que la soumission de formulaires.

Des instructions comme(ngSubmit)=”onLogin(f)” indiquent simplement que lorsque le formulaire est soumis, appelez la méthode“onLogin(f)” et transmettez le formulaire à cette fonction. Dans le divjumbotron, nous avons des balises de paragraphe qui s'afficheront dynamiquement en fonction de l'état de notre objet principal.

Ensuite, codons le fichier Typescript qui prendra en charge ce modèle.

4.2. Manuscrit

Dans le même répertoire, ouvrez le fichier app.component.ts. Dans ce fichier, nous ajouterons toutes les propriétés et les méthodes de script requises pour que notre modèle fonctionne:

import {Component} from "@angular/core";
import {Principal} from "./principal";
import {Response} from "@angular/http";
import {Book} from "./book";
import {HttpService} from "./http.service";

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent {
    selectedBook: Book = null;
    principal: Principal = new Principal(false, []);
    loginFailed: boolean = false;

    constructor(private httpService: HttpService){}

    ngOnInit(): void {
        this.httpService.me()
          .subscribe((response: Response) => {
              let principalJson = response.json();
              this.principal = new Principal(principalJson.authenticated,
              principalJson.authorities);
          }, (error) => {
              console.log(error);
        });
    }

    onLogout() {
        this.httpService.logout()
          .subscribe((response: Response) => {
              if (response.status === 200) {
                  this.loginFailed = false;
                  this.principal = new Principal(false, []);
                  window.location.replace(response.url);
              }
           }, (error) => {
               console.log(error);
       });
    }
}

Cette classe s'accroche à la méthode du cycle de vie angulaire,ngOnInit(). Dans cette méthode, nous appelons le point de terminaison/me pour obtenir le rôle et l'état actuels de l'utilisateur. Cela détermine ce que l’utilisateur voit sur la page principale. Cette méthode sera déclenchée chaque fois que ce composant est créé, ce qui est le moment idéal pour vérifier les propriétés de l'utilisateur pour les autorisations dans notre application.

Nous avons également une méthodeonLogout() qui déconnecte notre utilisateur et rétablit l'état de cette page à ses paramètres d'origine.

Il y a cependant de la magie ici. PropriétéhttpService déclarée dans le constructeur. Angular injecte cette propriété dans notre classe au moment de l'exécution. Angular gère les instances de classes de service singleton et les injecte à l'aide de l'injection de constructeur, tout comme Spring!

Ensuite, nous devons définir la classeHttpService.

4.3. HttpService

Dans le même répertoire, créez un fichier nommé“http.service.ts”. Dans ce fichier, ajoutez ce code pour prendre en charge les méthodes de connexion et de déconnexion:

import {Injectable} from "@angular/core";
import {Observable} from "rxjs";
import {Response, Http, Headers, RequestOptions} from "@angular/http";
import {Book} from "./book";
import {Rating} from "./rating";

@Injectable()
export class HttpService {

    constructor(private http: Http) { }

    me(): Observable {
        return this.http.get("/me", this.makeOptions())
    }

    logout(): Observable {
        return this.http.post("/logout", '', this.makeOptions())
    }

    private makeOptions(): RequestOptions {
        let headers = new Headers({'Content-Type': 'application/json'});
        return new RequestOptions({headers: headers});
    }
}

Dans cette classe, nous injectons une autre dépendance à l'aide de la construction DI d'Angular. Cette fois, c'est la classeHttp. Cette classe gère toutes les communications HTTP et nous est fournie par la structure.

Ces méthodes exécutent chacune une requête HTTP à l'aide de la bibliothèque HTTP d'angular. Chaque demande spécifie également un type de contenu dans les en-têtes.

Maintenant, nous devons faire une chose de plus pour enregistrer lesHttpService dans le système d'injection de dépendances. Ouvrez le fichierapp.module.ts et recherchez la propriété des fournisseurs. Ajoutez lesHttpService à ce tableau. Le résultat devrait ressembler à ceci:

providers: [HttpService],

4.4. Ajouter le principal

Ensuite, ajoutons notre objet DTO principal dans notre code Typescript. Dans le même répertoire, ajoutez un fichier appelé «principal.ts» et ajoutez le code suivant:

export class Principal {
    public authenticated: boolean;
    public authorities: Authority[] = [];
    public credentials: any;

    constructor(authenticated: boolean, authorities: any[], credentials: any) {
        this.authenticated = authenticated;
        authorities.map(
          auth => this.authorities.push(new Authority(auth.authority)))
        this.credentials = credentials;
  }

    isAdmin() {
        return this.authorities.some(
          (auth: Authority) => auth.authority.indexOf('ADMIN') > -1)
    }
}

export class Authority {
    public authority: String;

    constructor(authority: String) {
        this.authority = authority;
    }
}

Nous avons ajouté la classePrincipal et une classeAuthority. Ce sont deux classes DTO, un peu comme des POJO dans une application Spring. De ce fait, il n’est pas nécessaire d’enregistrer ces classes avec le système DI en angulaire.

Ensuite, configurons une règle de redirection pour rediriger les requêtes inconnues vers la racine de notre application.

4.5. 404 Manutention

Revenons au code Java du service de passerelle. Dans la classe où résideGatewayApplication, ajoutez une nouvelle classe appeléeErrorPageConfig:

@Component
public class ErrorPageConfig implements ErrorPageRegistrar {

    @Override
    public void registerErrorPages(ErrorPageRegistry registry) {
        registry.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND,
          "/home/index.html"));
    }

}

Cette classe identifiera toute réponse 404 et redirigera l'utilisateur vers“/home/index.html”. Dans une application à une seule page, c'est ainsi que nous gérons tout le trafic qui ne va pas vers une ressource dédiée, car le client doit gérer toutes les routes navigables.

Nous sommes maintenant prêts à lancer cette application et à voir ce que nous avons créé!

4.6. Construire et afficher

Exécutez maintenant «mvn compile» à partir du dossier de la passerelle. Cela compilera notre source Java et construira l'application Angular dans le dossier public. Lançons les autres applications cloud:config,discovery etzipkin. Ensuite, exécutez le projet de passerelle. Lorsque le service démarre, accédez àhttp://localhost:8080 pour voir notre application. Nous devrions voir quelque chose comme ceci:

image

Ensuite, suivons le lien vers la page de connexion:

image

Connectez-vous à l'aide des informations d'identification utilisateur / mot de passe. Cliquez sur «Connexion». Nous devrions être redirigés vers /home/index.html où notre application de page unique se charge.

image

Il semble que nosjumbotron indiquent que nous sommes connectés en tant qu’utilisateur! Déconnectez-vous maintenant en cliquant sur le lien dans le coin supérieur droit et connectez-vous en utilisant les informations d'identification deadmin/admincette fois.

image

Cela semble bon! Nous sommes maintenant connectés en tant qu’administrateur.

5. Conclusion

Dans cet article, nous avons vu à quel point il est facile d'intégrer une application d'une seule page dans notre système cloud. Nous avons adopté un cadre moderne et intégré une configuration de sécurité opérationnelle dans notre application.

En utilisant ces exemples, essayez d'écrire du code pour faire un appel auxbook-service ourating-service. Puisque nous avons maintenant des exemples d'appels HTTP et de données de câblage aux modèles, cela devrait être relativement facile.

Si vous souhaitez voir comment le reste du site est construit comme toujours, vous pouvez trouver le code sourceover on Github.