Frühlingswolke - Hinzufügen von Winkel 4

Frühlingswolke - Hinzufügen von Winkel 4

1. Überblick

In unserem letzten Spring Cloud-Artikel haben wirZipkin Support in unsere Anwendung aufgenommen. In diesem Artikel fügen wir unserem Stack eine Front-End-Anwendung hinzu.

Bisher haben wir ausschließlich am Back-End gearbeitet, um unsere Cloud-Anwendung zu erstellen. Aber was nützt eine Web-App, wenn es keine Benutzeroberfläche gibt? In diesem Artikel werden wir dieses Problem lösen, indem wir eine einseitige Anwendung in unser Projekt integrieren.

Wir werden diese App mitAngular undBootstrap schreiben. Der Stil von Angular 4-Code fühlt sich an wie das Codieren einer Spring-App, die für einen Spring-Entwickler ein natürlicher Crossover ist! Während der Front-End-Code Angular verwendet, kann der Inhalt dieses Artikels mit minimalem Aufwand problemlos auf jedes Front-End-Framework erweitert werden.

In diesem Artikel erstellen wir eine Angular 4-App und verbinden sie mit unseren Cloud-Diensten. Wir werden zeigen, wie Sie die Anmeldung zwischen einem SPA und Spring Security integrieren können. Wir zeigen auch, wie Sie mithilfe der Unterstützung von Angular für die HTTP-Kommunikation auf die Daten unserer Anwendung zugreifen können.

2. Gateway-Änderungen

Mit dem Front-End werden wir auf formularbasierte Anmeldung umsteigen und Teile der Benutzeroberfläche für privilegierte Benutzer sichern. Dies erfordert Änderungen an unserer Gateway-Sicherheitskonfiguration.

2.1. HttpSecurity aktualisieren

Aktualisieren wir zunächst die Methode vonconfigure(HttpSecurity http)in der Klasse unseres GatewaysSecurityConfig.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();
}

Zuerst fügen wir eine Standarderfolgs-URL hinzu, die auf/home/index.html verweist, da hier unsere Angular-App lebt. Als Nächstes konfigurieren wir die Ant-Matcher so, dass alle Anforderungen über das Gateway mit Ausnahme der Ressourcen vonEurekazugelassen werden. Dadurch werden alle Sicherheitsüberprüfungen an Back-End-Dienste delegiert.

Als Nächstes haben wir die URL für den erfolgreichen Abmeldevorgang entfernt, da die Standardumleitung zurück zur Anmeldeseite problemlos funktioniert.

2.2. Fügen Sie einen Hauptendpunkt hinzu

Fügen Sie als Nächstes einen Endpunkt hinzu, um den authentifizierten Benutzer zurückzugeben. Dies wird in unserer Angular-App verwendet, um sich anzumelden und die Rollen zu identifizieren, die unser Benutzer hat. Auf diese Weise können wir steuern, welche Aktionen sie auf unserer Website ausführen können.

Fügen Sie im Gateway-Projekt eineAuthenticationController-Klasse hinzu:

@RestController
public class AuthenticationController {

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

Die Steuerung gibt das aktuell angemeldete Benutzerobjekt an den Aufrufer zurück. Auf diese Weise erhalten wir alle Informationen, die wir zur Steuerung unserer Angular-App benötigen.

2.3. Landing Page hinzufügen

Fügen wir eine sehr einfache Zielseite hinzu, damit Benutzer etwas sehen, wenn sie zum Stammverzeichnis unserer Anwendung wechseln.

Fügen Sie insrc/main/resources/static, eineindex.html-Datei mit einem Link zur Anmeldeseite hinzu:




    
    Book Rater Landing


    

Book Rater

So many great things about the books

Login

3. Angular CLI und das Starterprojekt

Stellen Sie vor dem Starten eines neuen Angular-Projekts sicher, dass Sie die neuesten Versionen vonNode.js and npm installieren.

3.1. Installieren Sie die Angular CLI

Zu Beginn müssen wirnpm verwenden, um die Angular-Befehlszeilenschnittstelle herunterzuladen und zu installieren. Öffnen Sie ein Terminal und führen Sie Folgendes aus:

npm install -g @angular/cli

Dadurch wird die CLI global heruntergeladen und installiert.

3.2. Installieren Sie ein neues Projekt

Navigieren Sie im Terminal zum Gateway-Projekt und wechseln Sie in den Ordner gateway / src / main. Erstellen Sie ein Verzeichnis mit dem Namen "Eckig" und navigieren Sie dorthin. Von hier aus laufen:

ng new ui

Sei geduldig; Die CLI richtet ein brandneues Projekt ein und lädt alle JavaScript-Abhängigkeiten mit npm herunter. Es ist nicht ungewöhnlich, dass dieser Vorgang viele Minuten dauert.

Der Befehlng ist die Verknüpfung für die Angular-CLI, der Parameternewweist diese CLI an, ein neues Projekt zu erstellen, und der Befehluigibt unserem Projekt einen Namen.

3.3. Führen Sie das Projekt aus

Sobald der Befehlnewabgeschlossen ist. Navigieren Sie zum Ordnerui, der erstellt und ausgeführt wurde:

ng serve

Sobald das Projekt erstellt ist, navigieren Sie zuhttp://localhost:4200. Wir sollten dies im Browser sehen:

image

Herzliche Glückwünsche! Wir haben gerade eine Angular-App erstellt!

3.4. Installieren Sie Bootstrap

Verwenden wir npm, um Bootstrap zu installieren. Führen Sie im UI-Verzeichnis den folgenden Befehl aus:

npm install [email protected] --save

Dadurch wird Bootstrap in den Ordner node_modules heruntergeladen.

Öffnen Sie im Verzeichnisui die Datei.angular-cli.json. Dies ist die Datei, die einige Eigenschaften für unser Projekt konfiguriert. Suchen Sie die Eigenschaftapps > stylesund fügen Sie einen Dateispeicherort unserer Bootstrap-CSS-Klasse hinzu:

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

Dadurch wird Angular angewiesen, Bootstrap in die kompilierte CSS-Datei aufzunehmen, die mit dem Projekt erstellt wurde.

3.5. Legen Sie das Build Output Directory fest

Als Nächstes müssen wir Angular mitteilen, wo die Build-Dateien abgelegt werden sollen, damit unsere Spring Boot-App sie bedienen kann. Spring Boot kann Dateien von zwei Speicherorten im Ressourcenordner bereitstellen:

  • src/main/resources/static

  • src/main/resource/public

Da wir den statischen Ordner bereits verwenden, um einige Ressourcen für Eureka bereitzustellen, und Angular diesen Ordner bei jeder Ausführung eines Builds löscht, erstellen wir unsere Angular-App in den öffentlichen Ordner.

Öffnen Sie die Datei.angular-cli.json erneut und suchen Sie die Eigenschaftapps > outDir. Aktualisieren Sie diesestring:

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

Befindet sich das Angular-Projekt in src / main / angle / ui, wird es im Ordner src / main / resources / public erstellt. Wenn sich die App in einem anderen Ordner befindet, muss diese Zeichenfolge geändert werden, um den Speicherort korrekt festzulegen.

3.6. Automatisieren Sie den Build mit Maven

Zuletzt richten wir einen automatisierten Build ein, der ausgeführt wird, wenn wir unseren Code kompilieren. Diese Ant-Task führt die Angular CLI-Build-Task aus, wenn "MVN-Kompilierung" ausgeführt wird. Fügen Sie diesen Schritt der POM.xml des Gateways hinzu, um sicherzustellen, dass wir bei jeder Kompilierung die neuesten UI-Änderungen erhalten:


    maven-antrun-plugin
    
        
            generate-resources
            
                
                    
                        
                        
                        
                    
                    
                        
                        
                    
                
            
            
                run
            
        
    

Wir sollten beachten, dass für diese Einrichtung die Angular-CLI im Klassenpfad verfügbar sein muss. Das Verschieben dieses Skripts in eine Umgebung ohne diese Abhängigkeit führt zu Fehlern beim Erstellen.

Beginnen wir jetzt mit der Erstellung unserer Angular-Anwendung!

4. Winkelig

In diesem Abschnitt des Tutorials erstellen wir auf unserer Seite einen Authentifizierungsmechanismus. Wir verwenden die Standardauthentifizierung und folgen einem einfachen Ablauf, damit dies funktioniert.

Benutzer haben ein Anmeldeformular, in das sie ihren Benutzernamen und ihr Passwort eingeben können.

Als Nächstes verwenden wir ihre Anmeldeinformationen, um ein Base64-Authentifizierungstoken zu erstellen und den Endpunkt von“/me”anzufordern. Der Endpunkt gibt einPrincipal-Objekt zurück, das die Rollen dieses Benutzers enthält.

Zuletzt speichern wir die Anmeldeinformationen und den Principal auf dem Client, um sie für nachfolgende Anforderungen zu verwenden.

Mal sehen, wie das geht!

4.1. Vorlage

Navigieren Sie im Gateway-Projekt zusrc/main/angular/ui/src/app und öffnen Sie die Dateiapp.component.html. Dies ist die erste Vorlage, die Angular lädt und in der unsere Benutzer nach dem Anmelden landen.

Hier fügen wir Code hinzu, um eine Navigationsleiste mit einem Anmeldeformular anzuzeigen:



Book Rater App

Anyone can view the books.

Users can view and create ratings

Admins can do anything!

Dieser Code richtet eine Navigationsleiste mit Bootstrap-Klassen ein. In die Leiste ist ein Inline-Anmeldeformular eingebettet. Angular verwendet dieses Markup, um dynamisch mit JavaScript zu interagieren, um verschiedene Teile der Seite zu rendern und Dinge wie das Absenden von Formularen zu steuern.

Anweisungen wie(ngSubmit)=”onLogin(f)” geben lediglich an, dass beim Senden des Formulars die Methode“onLogin(f)” aufgerufen und das Formular an diese Funktion übergeben wird. Innerhalb desjumbotron div haben wir Absatz-Tags, die abhängig vom Status unseres Hauptobjekts dynamisch angezeigt werden.

Als nächstes codieren wir die Typescript-Datei, die diese Vorlage unterstützt.

4.2. Typoskript

Öffnen Sie im selben Verzeichnis die Datei app.component.ts. In dieser Datei werden alle Typoskript-Eigenschaften und Methoden hinzugefügt, die erforderlich sind, damit unsere Vorlage funktioniert:

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);
       });
    }
}

Diese Klasse knüpft an die Angular-Life-Cycle-MethodengOnInit() an. Bei dieser Methode rufen wir den Endpunkt von/meauf, um die aktuelle Rolle und den aktuellen Status des Benutzers abzurufen. Dies bestimmt, was der Benutzer auf der Hauptseite sieht. Diese Methode wird immer dann ausgelöst, wenn diese Komponente erstellt wurde. Dies ist ein guter Zeitpunkt, um die Eigenschaften des Benutzers auf Berechtigungen in unserer App zu überprüfen.

Wir haben auch eineonLogout()-Methode, die unseren Benutzer abmeldet und den Status dieser Seite auf die ursprünglichen Einstellungen zurücksetzt.

Hier ist allerdings etwas Magie los. Die im Konstruktor deklarierte EigenschafthttpService. Angular injiziert diese Eigenschaft zur Laufzeit in unsere Klasse. Angular verwaltet Singleton-Instanzen von Serviceklassen und fügt sie wie Spring!

Als nächstes müssen wir die KlasseHttpServicedefinieren.

4.3. HttpService

Erstellen Sie im selben Verzeichnis eine Datei mit dem Namen“http.service.ts”. Fügen Sie in dieser Datei diesen Code hinzu, um die Anmelde- und Abmeldemethoden zu unterstützen:

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});
    }
}

In dieser Klasse injizieren wir eine weitere Abhängigkeit mithilfe des DI-Konstrukts von Angular. Diesmal ist es die KlasseHttp. Diese Klasse verwaltet die gesamte HTTP-Kommunikation und wird uns vom Framework bereitgestellt.

Diese Methoden führen jeweils eine HTTP-Anforderung unter Verwendung der HTTP-Bibliothek von angle aus. Jede Anforderung gibt auch einen Inhaltstyp in den Kopfzeilen an.

Jetzt müssen wir noch etwas tun, um dieHttpServiceim Abhängigkeitsinjektionssystem zu registrieren. Öffnen Sie die Dateiapp.module.tsund suchen Sie die Provider-Eigenschaft. Fügen Sie diesem Array dieHttpService hinzu. Das Ergebnis sollte so aussehen:

providers: [HttpService],

4.4. Principal hinzufügen

Als Nächstes fügen wir unser Haupt-DTO-Objekt in unseren Typescript-Code ein. Fügen Sie im selben Verzeichnis eine Datei mit dem Namen "principal.ts" hinzu und fügen Sie diesen Code hinzu:

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;
    }
}

Wir haben die KlassePrincipalund die KlasseAuthorityhinzugefügt. Dies sind zwei DTO-Klassen, ähnlich wie POJOs in einer Spring-App. Aus diesem Grund müssen wir diese Klassen nicht im DI-System in Angular registrieren.

Als Nächstes konfigurieren wir eine Umleitungsregel, um unbekannte Anforderungen an das Stammverzeichnis unserer Anwendung umzuleiten.

4.5. 404 Handhabung

Navigieren wir zurück zum Java-Code für den Gateway-Dienst. Fügen Sie in der Klasse where (t0) s eine neue Klasse mit dem NamenErrorPageConfig hinzu:

@Component
public class ErrorPageConfig implements ErrorPageRegistrar {

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

}

Diese Klasse identifiziert jede 404-Antwort und leitet den Benutzer zu“/home/index.html” um. In einer App mit nur einer Seite behandeln wir auf diese Weise den gesamten Datenverkehr, der nicht zu einer dedizierten Ressource geleitet wird, da der Client alle navigierbaren Routen verarbeiten sollte.

Jetzt können wir diese App starten und sehen, was wir erstellt haben!

4.6. Erstellen und anzeigen

Führen Sie nun "mvn compile" aus dem Gateway-Ordner aus. Dadurch wird unsere Java-Quelle kompiliert und die Angular-App im öffentlichen Ordner erstellt. Starten wir die anderen Cloud-Anwendungen:config,discovery undzipkin. Führen Sie dann das Gateway-Projekt aus. Wenn der Dienst gestartet wird, navigieren Sie zuhttp://localhost:8080, um unsere App anzuzeigen. Wir sollten so etwas sehen:

image

Folgen Sie als Nächstes dem Link zur Anmeldeseite:

image

Melden Sie sich mit den Benutzer- / Kennwort-Anmeldeinformationen an. Klicken Sie auf "Anmelden", und wir sollten zu /home/index.html weitergeleitet werden, wo unsere App für eine einzelne Seite geladen wird.

image

Es sieht so aus, als ob unserejumbotron anzeigen, dass wir als Benutzer angemeldet sind! Melden Sie sich jetzt ab, indem Sie auf den Link in der oberen rechten Ecke klicken, und melden Sie sich diesmal mit den Anmeldeinformationen vonadmin/adminan.

image

Sieht gut aus! Jetzt sind wir als Administrator angemeldet.

5. Fazit

In diesem Artikel haben wir gesehen, wie einfach es ist, eine einzelne Seiten-App in unser Cloud-System zu integrieren. Wir haben ein modernes Framework verwendet und eine funktionierende Sicherheitskonfiguration in unsere Anwendung integriert.

Versuchen Sie anhand dieser Beispiele, Code zu schreiben, umbook-service oderrating-service aufzurufen. Da wir nun Beispiele für das Tätigen von HTTP-Aufrufen und das Verbinden von Daten mit den Vorlagen haben, sollte dies relativ einfach sein.

Wenn Sie sehen möchten, wie der Rest der Site wie immer aufgebaut ist, finden Sie den Quellcodeover on Github.