1. Einführung

Das Ziel dieses Tutorials ist es, mithilfe von Keycloak und Angular eine einfache Web-Anwendung zu erstellen, welche eine Authentifizierung und Autorisierung mit Keycloak implementiert und somit Zugriffsrechte auf bestimmte Bereiche der Anwendung definiert.

1.1. Voraussetzungen

Folgendes wird benötigt:

  • Entwicklungsumgebung (WebStorm, Visual Studio Code, …​)

  • Angular CLI

  • Node.js

  • Keycloak

Das folgende Tutorial baut auf dem Tutorial Securing Quarkus Backends with Keycloak auf. Daher wird das Durcharbeiten des Tutorials benötigt, um das folgende Tutorial absolvieren zu können. Wobei nur der PBAC-Teil (Policy-Based Access Control) benötigt wird.

2. Setup

2.1. Keycloak installieren

2.1.1. Docker-Image pullen

docker pull quay.io/keycloak/keycloak:26.1.4
Für das Tutorial wird Keycloak in der Version 26.1.4 verwendet. Es ist empfohlen ebenfalls mit der Version 26.1.4 zu arbeiten, um mögliche Unterschiede in der Funktionalität bzw. Nutzung zu vermeiden.

2.1.2. Docker-Image starten

docker run -d \ (1)
    -p 8000:8080 \ (2)
    -e KEYCLOAK_ADMIN=admin \ (3)
    -e KEYCLOAK_ADMIN_PASSWORD=<PASSWORD> \ (4)
    -e KC_PROXY=edge \ (5)
    --restart always \ (6)
    -v /<PATH>:/opt/jboss/keycloak/standalone/data \ (7)
    quay.io/keycloak/keycloak:26.1.4 \ (8)
    start-dev (9)
1 Der -d-Flag (detached mode) sorgt dafür, dass der Container im Hintergrund läuft.
2 Bindet Port 8080 des Containers an Port 8000 des Hosts, sodass Keycloak über diesen Port erreichbar ist. (Port-Forwarding)
3 Legt den Benutzernamen des Keycloak-Administrators auf admin fest.
4 Legt das Passwort für den Keycloak-Administrator fest. (<PASSWORD> mit einem beliebigen Passwort ersetzen)
5 Legt den Proxy-Typ auf Edge fest. Keycloak läuft hierbei hinter einem Reverse Proxy.
6 Konfiguriert den Container so, dass er immer automatisch neu gestartet wird, falls der Container beispielsweise abstürzt.
7 Mountet ein Volume, um Keycloak-Daten zu speichern. Dadurch bleiben die Daten persistent, auch wenn der Container neu gestartet wird.
8 Gibt das Keycloak-Docker-Image mit Version 26.1.4 an.
9 Befehl zum Starten von Keycloak im Entwicklungsmodus. Dies bedeutet ebenfalls, dass einige Sicherheitsfeatures deaktiviert sind und das System schneller startet.

2.2. Angular einrichten

2.2.1. Angular CLI installieren

npm install -g @angular/cli
Für das Tutorial wird Angular in der Version 19.2.5 verwendet. Es ist empfohlen ebenfalls mit der Version 19.2.5 zu arbeiten, um mögliche Unterschiede in der Funktionalität bzw. Nutzung zu vermeiden.

3. Keycloak konfigurieren

Für die folgenden Schritte muss Keycloak gestartet sein. Siehe Setup.

Falls bereits ein Realm, die passenden Rollen oder Benutzer im vorherigen Tutorial Securing Quarkus Backends with Keycloak erstellt worden sind, können die jeweiligen Schritte übersprungen werden.

Der Realm-Name des folgenden Tutorials weicht vom Realm-Name des vorherigen Tutorials ab, jedoch ist dies kein Problem. Es kann wie gehabt im bestehenden Realm weitergearbeitet werden, auch wenn der Realm-Name unterschiedlich ist, jedoch muss im Angular-Projekt beim Initialisieren von Keycloak der passende Realm-Name angegeben werden.

Was jedoch abgesehen vom Tutorial Securing Quarkus Backends with Keycloak nicht übersprungen werden kann, ist die Erstellung des Clients. Dieser muss für das Tutorial erstellt werden.

3.1. Login

Zuerst muss muss man sich auf der Keycloak-Webseite anmelden. Hierfür muss man die URL http://localhost:8000 in den Browser eingeben.

Daraufhin sollte die Keycloak-Login-Seite erscheinen, welche wie folgt aussieht:

keycloak login page
Figure 1. Keycloak-Login-Seite

Nun muss man sich mit den Benutzernamen admin und dem zuvor festgelegten Passwort anmelden.

3.2. Realm

Bei erfolgreichem Login wird man auf folgende Seite weitergeleitet:

keycloak start page
Figure 2. Keycloak-Startseite

3.2.1. Was ist ein Realm?

Ein Realm in Keycloak ist eine isolierte Umgebung, in der Benutzer, Rollen und Clients verwaltet werden. Man kann sich einen Realm wie eine eigene Benutzerverwaltung für eine bestimmte Anwendung oder ein System vorstellen.

Ein Realm ist wie eine eigene "Firma" in Keycloak. Jede Firma hat ihre eigenen Mitarbeiter (Benutzer), Abteilungen (Rollen) und Anwendungen (Clients).

Innerhalb eines Realms können sich Benutzer anmelden, Berechtigungen erhalten und Zugriff auf bestimmte Anwendungen bekommen.

Deutsche Synonyme für Realm sind Reich, Bereich und Königreich.

3.2.2. Erstellen eines neuen Realms

Standardmäßig gibt es in Keycloak den Master-Realm. Dieser dient aber nur zur Verwaltung von Keycloak selbst. Daher muss für das Tutorial ein neuer Realm erstellt werden:

keycloak realm create page
Figure 3. Erstellen eines neuen Realms
Der Realm-Name muss innerhalb der eigenen Keycloak-Instanz eindeutig sein und sollte für das Tutorial den Namen angular-policy-tutorial erhalten, um mögliche Fehler bzw. Unterschiede im weiteren Verlauf des Tutorials zu vermeiden.
keycloak realm create page 01
Figure 4. Felder zur Erstellung eines Realms ausfüllen
Falls man ein Realm temporär deaktivieren möchte, ist es besser den Schalter (Enabled) im Nachhinein umzulegen, anstatt den Realm komplett zu löschen.

3.3. Client

keycloak client page
Figure 5. Erstellen eines neuen Clients

3.3.1. Was ist ein Client?

Ein Client in Keycloak ist eine Anwendung oder ein Dienst, der die Authentifizierung und Autorisierung über Keycloak nutzt. Der Client kann eine Web-App, eine mobile App, eine API oder ein anderer Dienst sein, der auf Benutzeranmeldungen angewiesen ist.

3.3.2. Erstellen eines neuen Clients

Seite 1 (General settings)
keycloak client create page 01
Figure 6. Felder zur Erstellung eines Clients ausfüllen (Seite 1)
Beschreibung der Felder (Seite 1)
1 Der Client type in Keycloak bestimmt, welches Protokoll der Client für die Authentifizierung und Autorisierung verwendet. Hierbei gibt es zwei Optionen. Einerseits gibt es OpenID Connect, welches eine Erweiterung von OAuth 2.0 ist und für moderne Webanwendungen verwendet wird. Andererseits gibt es SAML (Security Assertion Markup Language), welches ein älteres Protokoll ist und für Single Sign-On (SSO) verwendet wird. Für das Tutorial ist OpenID Connect geeignet.
2 Client ID repräsentiert einen eindeutigen Namen des Clients, welcher innerhalb des Realms eindeutig sein muss.
3 Das Feld Name ist optional und dient zur Beschreibung des Clients.
4 Das Feld Description ist ebenfalls optional und dient zur detaillierteren Beschreibung des Clients, um beispielsweise den Zweck des Clients zu beschreiben.
5 Always display in UI ist ein Flag, welches bei einer Aktivierung dafür sorgt, dass der Client auf der Keycloak-Anmeldeseite als auswählbare Anwendung angezeigt wird. Bei einer Deaktivierung wird der Client nicht auf der Anmeldeseite angezeigt. Falls Benutzer sich direkt für eine bestimmte App anmelden sollen, kann es sinnvoll sein, den Client in der UI anzuzeigen. Für das Tutorial hingegen ist es nicht notwendig, den Client in der UI anzuzeigen.

Mit dem Button Next wird die Eingabe bestätigt und man wird auf die zweite Seite weitergeleitet.

Seite 2 (Capability config)
keycloak client create page 02
Figure 7. Felder zur Erstellung eines Clients ausfüllen (Seite 2)
Beschreibung der Felder (Seite 2)
1 Wenn die Client authentication deaktiviert ist, benötigt der Client keine Authentifizierung, um auf Keycloak-Ressourcen zuzugreifen. Wenn das Feld deaktiviert ist, muss der Client sich mit einem geheimen Schlüssel (Client Secret) authentifizieren, bevor er eine Authentifizierungsanfrage stellen kann. Diese Option wird bei Servern bzw. Backend-Services verwendet.
2 Bei Deaktivierung der Funktion Authorization kann der Client frei auf geschützte Ressourcen zugreifen, ohne dass spezielle Berechtigungsprüfungen durch Keycloak erfolgen. Bei Aktivierung nutzt Keycloak sein Authorization Service-Feature, um Berechtigungen für diesen Client zu verwalten.
3 Mit dem Authentication flow wird festgelegt, welche OAuth 2.0-Flows der Client nutzen darf:
  • Standard Flow

    • Wird für Single Page Applications (SPAs) wie Angular empfohlen.

    • Der Benutzer meldet sich über Keycloak an, Keycloak gibt einen Authorization Code zurück, den das Frontend nutzt, um ein Access Token zu holen.

  • Direct Access Grants

    • Ermöglicht es Anwendungen, Benutzernamen und Passwort direkt an Keycloak zu senden, um ein Token zu bekommen.

  • Implicit Flow

    • Der Access Token wird direkt im Frontend vergeben.

  • Service accounts roles

    • Wird bei Backend-Services verwendet, welche ohne Benutzerinteraktion rollenbasierte Zugriffe benötigen.

  • OAuth 2.0 Device Authorization Grant

    • Wird bei Geräten mit beschränktem UI (Smart-TVs, IoT-Geräte, Konsolen) verwendet.

  • OIDC CIBA Grant

    • Wird für spezielle Szenarien wie Banking-Anwendungen oder Zwei-Faktor-Authentifizierung genutzt.

Mit dem Button Next wird die Eingabe bestätigt und man wird auf die letzte Seite weitergeleitet.

Seite 3 (Login settings)
keycloak client create page 03
Figure 8. Felder zur Erstellung eines Clients ausfüllen (Seite 3)
Beschreibung der Felder (Seite 2)
1 Die Root URL repräsentiert die Basis-URL der Anwendung, welche für diesen Client in Keycloak registriert wird. Da im weiteren Verlauf des Tutorials eine Angular-Anwendung erstellt wird, sollte die Root URL http://localhost:4200 sein, da es sich um eine lokale Angular-Anwendung handelt.
2 Die Home URL stellt jene URL da, auf die der Benutzer nach erfolgreicher Authentifizierung weitergeleitet wird. In diesem Tutorial wird der Benutzer nach einer erfolgreichen Authentifizierung auf die Home-Page (http://localhost:4200) weitergeleitet.
3 Die Valid redirect URIs bilden weitere zulässige URLs ab, auf die der Benutzer nach der Authentifizierung weitergeleitet werden darf. Mit http://localhost:4200/ wird das Weiterleiten zu sämtlichen Unterseiten der Angular-Anwendung erlaubt.
4 Die Valid post logout redirect URIs stellen URLs dar, auf die der Benutzer nach dem Logout weitergeleitet werden darf. Mit http://localhost:4200/ wird das Weiterleiten zu sämtlichen Unterseiten der Angular-Anwendung erlaubt.
5 Die Web Origins stellen die URLs fest, von denen aus die Anfragen an Keycloak gesendet werden können. Hierbei sollte die nur die tatsächlich URL des Clients eingetragen werden. In diesem Fall ist es http://localhost:4200.

Mit dem Button Save wird die Eingabe bestätigt und der Client wird erstellt.

Nach dem man auf den Button Save geklickt hat, wird man auf eine Überblicksseite weitergeleitet, bei der man noch einmal alle Konfigurationen überprüfen und final bestätigen kann.

3.4. Roles

keycloak role page
Figure 9. Erstellen einer neuen Role

3.4.1. Was ist eine Role?

Roles (Rollen) in Keycloak sind eine Möglichkeit, Benutzer zu gruppieren und ihre Berechtigungen zu definieren. Sie bestimmen, welche Aktionen ein Benutzer ausführen darf.

3.4.2. Erstellen mehrerer neuer Rollen

Es ist möglich Rollen auf Realm- und Client-Ebene zu erstellen. In diesem Tutorial werden die Rollen auf der Realm-Ebene erstellt.
Rolle 1

Zuerst wird eine Rolle namens admin erstellt.

keycloak role01 create page 02
Figure 10. Erstellen der Rolle admin
Rolle 2

Weiters wird eine weitere Rolle namens user erstellt.

keycloak role02 create page 01
Figure 11. Erstellen der Rolle user

Nun sind die Rollen admin und user erstellt worden und stehen zur Vergabe an User zur Verfügung.

3.5. User

keycloak user01 create page 01
Figure 12. Erstellen eines neuen Users

3.5.1. Erstellen mehrerer neuer User

Es ist möglich User manuell zu erstellen, aber auch aus externen Quellen zu importieren. In diesem Tutorial werden die User manuell erstellt.
User 1

Zuerst wird ein User namens John Doe wie folgt erstellt:

keycloak user01 create page 02
Figure 13. Erstellen des Users John Doe

Nun werden die Credentials bzw. das Passwort für den User John Doe gesetzt.

keycloak user01 create page 03
Figure 14. Erstellen der Credentials

Nun wird das Passwort (john123) für den User John Doe gesetzt.

keycloak user01 create page 04
Figure 15. Erstellen des Passworts
Das Flag Temporary wird für das Tutorial deaktiviert, da sonst beim nächsten Login das Passwort geändert werden muss.

Zuletzt muss dem User John Doe noch eine Rolle zugewiesen werden.

keycloak user01 create page 05
Figure 16. Zuweisen der Rolle

Es werden die Rollen admin und user zugewiesen.

keycloak user01 create page 06
Figure 17. Zuweisen der Rolle admin und user
User 2

Nun wird ein User namens Jane Doe wie folgt erstellt:

keycloak user02 create page 01
Figure 18. Erstellen des Users Jane Doe

Nun wird das Passwort (jane123) für Jane Doe gesetzt.

keycloak user02 create page 02
Figure 19. Erstellen des Passworts

Zuletzt wird noch die Rolle user zugewiesen.

keycloak user02 create page 03
Figure 20. Zuweisen der Rolle user

4. Backend

Das folgende Tutorial baut auf dem Tutorial Securing Quarkus Backends with Keycloak auf. Daher wird das Durcharbeiten des Tutorials benötigt, um das folgende Tutorial absolvieren zu können. Wobei nur der PBAC-Teil (Policy-Based Access Control) benötigt wird.

4.1. application.properties anpassen

Im Backend (mit PBAC), welches im Tutorial Securing Quarkus Backends with Keycloak erstellt wurde, muss folgende Konfiguration hinzugefügt werden:

src/main/resources/application.properties
quarkus.datasource.db-kind = postgresql
quarkus.datasource.username = app
quarkus.datasource.password = app
quarkus.datasource.jdbc.url = jdbc:postgresql://localhost:5432/db

quarkus.hibernate-orm.database.generation=drop-and-create
quarkus.hibernate-orm.physical-naming-strategy=org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy

quarkus.oidc.auth-server-url=http://localhost:8000/realms/angular-policy-tutorial
quarkus.oidc.client-id=backend

quarkus.oidc.credentials.secret=<CLIENT_SECRET>

quarkus.keycloak.policy-enforcer.enable=true

quarkus.devservices.enabled=false

#### KOMMT NEU DAZU ####
quarkus.http.cors.enabled=true (1)
quarkus.http.cors.origins=/.*/ (2)
1 Aktiviert CORS-Unterstützung im Quarkus-HTTP-Server. Ohne diese Einstellung würden Cross-Origin-Anfragen vom Browser blockiert werden.
2 Legt fest, dass alle Domains erlaubt sind. Dies ist in der Entwicklungsumgebung sinnvoll. In einer Produktionsumgebung sollte dies jedoch restriktiver gesetzt werden, um Sicherheitsrisiken zu vermeiden.

5. Angular

Für das Tutorial wird Angular in der Version 19.2.5 verwendet. Siehe Angular-Setup.

5.1. Angular-Projekt erstellen

Mit der Angular CLI kann ein neues Angular-Projekt wie folgt erstellt werden:

ng new ng-keycloak-policy-demo

Bei der Erstellung des Projekts werden einige Fragen gestellt, die wie folgt beantwortet werden:

  • Stylesheet format: CSS

  • Server-side rendering and Static Site Generation: No

Nun wird das Projekt in einer beliebigen IDE, welche Angular unterstützt, geöffnet, z. B. WebStorm oder Visual Studio Code.

Das Projekt kann jederzeit, sofern man sich im Projektverzeichnis befindet, mit folgendem Befehl gestartet werden:

ng serve

Das Projekt ist somit unter der URL http://localhost:4200 erreichbar.

5.2. Library installieren

Um die Keycloak-Integration in Angular zu ermöglichen, werden die keycloak-angular- und die keycloak-js-Library benötigt. Diese können mit dem folgenden Befehl installiert werden:

npm install keycloak-angular keycloak-js

5.3. Keycloak initialisieren

Um Keycloak in Angular zu initialisieren, muss die bestehende TypeScript-Datei app.config.ts erweitert werden.

app.config.ts
import { ApplicationConfig, APP_INITIALIZER, inject } from '@angular/core';
import { provideRouter } from '@angular/router';
import { HttpInterceptorFn, provideHttpClient, withInterceptors } from '@angular/common/http';
import { KeycloakService } from 'keycloak-angular';
import { routes } from './app.routes';

const keycloakInterceptor: HttpInterceptorFn = (req, next) => {
  const keycloak = inject(KeycloakService); (1)
  const instance = keycloak.getKeycloakInstance(); (2)

  if (instance?.token) {
    req = req.clone({
      setHeaders: {
        Authorization: `Bearer ${instance.token}` (3)
      }
    });
  }
  return next(req);
};

function initializeKeycloak() { (4)
  const keycloak = inject(KeycloakService);
  return () =>
    keycloak.init({
      config: {
        url: 'http://localhost:8000', (5)
        realm: 'angular-policy-tutorial', (6)
        clientId: 'angular-policy' (7)
      },
      initOptions: {
        onLoad: 'login-required', (8)
        checkLoginIframe: false (9)
      }
    });
}

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes),
    provideHttpClient(
      withInterceptors([keycloakInterceptor]) (10)
    ),
    {
      provide: APP_INITIALIZER, (11)
      useFactory: initializeKeycloak,
      multi: true
    },
    KeycloakService (12)
  ]
};
1 Der KeycloakService wird mithilfe von inject() abgerufen, um innerhalb des Interceptors auf den aktuellen Authentifizierungsstatus zuzugreifen.
2 Über getKeycloakInstance() wird die native Keycloak-Instanz abgerufen, in der u. a. das Token gespeichert ist.
3 Falls ein Token vorhanden ist, wird es als Authorization: Bearer …​ Header an den HTTP-Request angehängt.
4 Die Funktion initializeKeycloak() konfiguriert und startet den Keycloak-Service beim App-Start.
5 Die URL des Keycloak-Servers.
6 Der Name des Realms, in dem sich der Client befindet.
7 Die Client-ID, mit der sich die Angular-App bei Keycloak authentifiziert.
8 onLoad: 'login-required' bedeutet, dass ein Benutzer automatisch zum Login weitergeleitet wird, wenn er nicht eingeloggt ist.
9 checkLoginIframe: false deaktiviert die regelmäßige Prüfung des Login-Status via verstecktem Iframe. Normalerweise prüft Keycloak regelmäßig in einem versteckten <iframe>, ob der Benutzer noch eingeloggt ist (Single-Sign-On-Session-Check). Der Vorteil bei der Deaktivierung ist, dass weniger HTTP-Traffic entsteht.
10 withInterceptors([keycloakInterceptor]) sorgt dafür, dass alle HTTP-Requests automatisch mit dem Access-Token versehen werden.
11 Mit APP_INITIALIZER wird initializeKeycloak() beim Start der Anwendung ausgeführt, noch bevor die App gerendert wird.
12 KeycloakService wird hier als Provider registriert, damit er überall in der App verwendet werden kann.

Nun sollte man beim Starten der App auf die folgende Seite weitergeleitet werden:

keycloak login site
Figure 21. Keycloak-Login-Seite

Man kann sich nun entweder mit dem User John Doe oder mit dem User Jane Doe, welche beide zuvor im Tutorial erstellt wurden, anmelden.

Bei erfolgreichem Login sollte man auf die folgende Seite weitergeleitet werden:

angular start page
Figure 22. Angular-Startseite

5.4. Model erstellen

Um die Daten, welche vom Backend zurückgegeben werden, zu speichern, wird ein Model benötigt. Dieses Model sieht wie folgt aus:

src/shared/model/vehicle.ts
export interface Vehicle{
    id: number;
    make: string;
    model: string;
    year: number;
}

5.5. Service erstellen

Um Daten aus dem Backend zu holen, wird ein Service benötigt. Dieses Service wird wie folgt erstellt:

src/shared/services
ng generate service vehicle

Die generierte Service-Klasse sieht wie folgt aus:

src/shared/services/vehicle.service.ts
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Vehicle } from '../model/vehicle';

@Injectable({
  providedIn: 'root'
})
export class VehicleService {
  private http = inject(HttpClient);
  private backendUrl = 'http://localhost:8080/vehicle';

  getAllVehicles() {
    return this.http.get<Vehicle[]>(`${this.backendUrl}/`);
  }

  getVehicle(id: number) {
    return this.http.get<Vehicle>(`${this.backendUrl}/${id}`);
  }
}

Nach dem Erstellen des Models und des Services sollte die Projektstruktur wie folgt aussehen:

ZSv12iD028NXVUyounLo5T7NHcBYe4CWjo aq6Nfzl4  9UQdFDfZdhGyMeRBl7WhOrmawifzg1A8Hw3Uk  JxLoGcaFXTE9rSJHP s52dcQeBxkCzn mQ5tuni0

5.6. Komponente anpassen

Um die Daten aus dem Backend anzuzeigen, wird die bestehende Komponente app.component.ts angepasst.

src/app/app.component.ts
import { Component, inject, OnInit } from '@angular/core';
import { VehicleService } from '../shared/services/vehicle.service';
import { Vehicle } from '../shared/model/vehicle';
import { FormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { RouterOutlet } from '@angular/router';
import { KeycloakService } from 'keycloak-angular';

@Component({
  selector: 'app-root',
  imports: [FormsModule, CommonModule, RouterOutlet],
  templateUrl: './app.component.html',
  styleUrl: './app.component.css'
})
export class AppComponent implements OnInit{
  title = 'ng-keycloak-policy-demo';

  keycloakService = inject(KeycloakService);
  vehicleService = inject(VehicleService);

  allVehicles: Vehicle[] = [];
  vehicleById: Vehicle | null = null;
  vehicleId: number | null = null;

  isAdmin: boolean = false;
  isUser: boolean = false;

  ngOnInit(){ (1)
    this.isAdmin = this.keycloakService.getUserRoles().includes('admin');
    this.isUser = this.keycloakService.getUserRoles().includes('user');
  }

  getAllVehicles(){
    this.vehicleService.getAllVehicles().subscribe((vehicles) => { (2)
      this.allVehicles = vehicles;
    })
  }

  getVehicleById(){
    if(this.vehicleId){
      this.vehicleService.getVehicle(this.vehicleId).subscribe((vehicle) => { (3)
        this.vehicleById = vehicle;
      })
    }
    else{
      console.log('The vehicle-id is not set!');
    }
  }
}
1 Im ngOnInit() prüft die Komponente, ob der eingeloggte Benutzer die Rollen admin oder user hat. Damit kann z. B. im Template gesteuert werden, ob bestimmte Buttons sichtbar sind.
2 Die Methode getAllVehicles() ruft alle Fahrzeuge vom Backend ab und speichert sie in der allVehicles-Liste. Die Daten werden dann im Template angezeigt, jedoch nur, wenn der eingeloggte Benutzer die Rolle admin hat.
3 Die Methode getVehicleById() holt ein einzelnes Fahrzeug basierend auf der eingegebenen vehicleId und speichert es in vehicleById. Hierfür wird nur die Rolle user benötigt.

Nun muss die HTML-Datei app.component.html angepasst werden, um die Daten anzuzeigen.

src/app/app.component.html
<div class="container">
  <h1>{{title}}</h1>

  <div class="button-group">

    <div class="all-vehicles">
      <button
        [disabled]="!isAdmin" (1)
        (click)="getAllVehicles()"
        class="btn btn-primary">
        Get all vehicles
      </button>

      <div class="vehicle-list">
        @for (vehicle of allVehicles; track vehicle) {
          <p>{{ vehicle.id }} {{ vehicle.make }} {{ vehicle.model }} {{ vehicle.year }}</p>
        }
      </div>
    </div>

    <div class="by-id">
      @if (isUser) {
        <select [(ngModel)]="vehicleId" class="id-input">
          <option [ngValue]="1">1</option>
          <option [ngValue]="2">2</option>
          <option [ngValue]="3">3</option>
        </select>
      }
      <button
        (click)="getVehicleById()"
        [disabled]="!vehicleId || !isUser" (2)
        class="btn btn-secondary">
        Get vehicle by id
      </button>

      <div class="vehicle-single">
        @if (vehicleById) {
          <p>{{ vehicleById.id }} {{ vehicleById.make }} {{ vehicleById.model }} {{ vehicleById.year }}</p>
        }
      </div>
    </div>

  </div>
</div>

<router-outlet></router-outlet>
1 Der Button Get all vehicles ist nur sichtbar, wenn der eingeloggte Benutzer die Rolle admin hat. Andernfalls ist der Button deaktiviert.
2 Der Button Get vehicle by id ist nur sichtbar, wenn der eingeloggte Benutzer die Rolle user hat und eine vehicleId gesetzt ist. Andernfalls ist der Button deaktiviert.

Zuletzt wird noch die CSS-Datei app.component.css angepasst, um die Daten etwas schöner darzustellen.

src/app/app.component.css
.container {
    max-width: 1000px;
    margin: 2rem auto;
    padding: 2rem;
    font-family: Arial, sans-serif;
    background-color: #f9f9f9;
    border-radius: 12px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

.container h1 {
    text-align: center;
    font-size: 2rem;
    margin-bottom: 2rem;
    color: #333;
}

.button-group {
    display: flex;
    gap: 2rem;
    justify-content: space-between;
    flex-wrap: wrap;
}

.all-vehicles {
    flex: 1;
    min-width: 280px;
}

.by-id {
    flex: 1;
    min-width: 280px;
}

.btn {
    padding: 0.6rem 1.2rem;
    border: none;
    border-radius: 8px;
    font-size: 1rem;
    cursor: pointer;
    transition: background-color 0.3s ease;
    width: 100%;
    margin-bottom: 1rem;
}

.btn-primary {
    background-color: #007bff;
    color: white;
}

.btn-primary:disabled {
    background-color: #b3d4fc;
    cursor: not-allowed;
}

.btn-secondary {
    background-color: #6c757d;
    color: white;
}

.btn-secondary:disabled {
    background-color: #d6d6d6;
    cursor: not-allowed;
}

.id-input {
    width: 100%;
    padding: 0.5rem;
    border: 1px solid #ccc;
    border-radius: 6px;
    font-size: 1rem;
    margin-bottom: 1rem;
}

.vehicle-list p, .vehicle-single p {
    background-color: #ffffff;
    padding: 0.5rem 1rem;
    border-left: 4px solid #007bff;
    border-radius: 6px;
    margin-bottom: 0.5rem;
    color: #444;
}

5.7. Demo

Nun kann die Angular-App gestartet werden.

5.7.1. Admin-Sicht

Bei einem Login des Users John Doe mit der Rolle admin sollte die Seite wie folgt aussehen:

angular start page admin
Figure 23. Angular-Startseite mit Admin-Rechten

5.7.2. User-Sicht

Bei einem Login des Users Jane Doe mit der Rolle user sollte die Seite wie folgt aussehen:

angular start page user
Figure 24. Angular-Startseite mit User-Rechten
Die App kann nun vielfältig und vor allem sicher um zahlreiche weitere Features erweitert werden.