Fullstack-IAM Teil 3: Angular Frontend als Client mit Keycloak & Resource Server Integration
In diesem dritten Teil der Blogreihe, wird aufgezeigt, wie sich die Integration einer Client App (Angular) mit Keycloak und einem geschützten Resource Server realisieren lässt.
Notwendiges Wissen
- OAuth 2.0
- Authentisierung, Authentifizierung und Autorisierung
- Keycloak
- Entwicklungskenntnisse in
Technische Voraussetzungen
- Laufende Keycloak Instanz (siehe Teil1 der Blogreihe)
- Laufender Resource Server (siehe Teil2 der Blogreihe)
- IDE für Typescript
- Node / NPM
- Angular CLI
Angular (Client App)
Bootstrapping Angular
ng generate angular-client
- Erzeugt eine Angular Anwendung mit dem Namen angular-client
- Bei der Frage ob wir den Router hinzufügen möchten, geben wir
n
ein und verneinen somit
cd angular-client
- Navigation in das Projekt
ng generate service secured-api
- Erzeugt eine Serviceklasse in unserem Projekt, diese dient für die Implementierung der Schnittstellen aufrufe an den Resource Server
npm install angular-oauth2-oidc --save
- Fügt eine Abhängigkeit hinzu, mit der die OpenId-Connect Prozesse für den Client optimal unterstützt werden.
Security Konfiguration
- Öffnen von
src/app/app.module.ts
- Hinzufügen des HttpClientModule
- Wird benötigt um die Schnittstelle des Resource Servers aufzurufen
- Hinzufügen des OAuthModules
- Enthält die Url des Resource Servers, sowie ein Flag ob das accessToken immer mitgesendet werden soll, wenn der Resource Server aufgerufen wird
- Hinzufügen des HttpClientModule
- Erstellen einer neuen Datei
proxy.conf.json
- Implementierung des Proxies
- Öffnen von
angular.json
- Hinzufügen der proxy.conf.json Datei in den ng serve Befehl
API-Service implementieren
- Öffnen von
src/app/secured-api-service.ts
- Definition der Klassenvariable
- httpClient: HttpClient
- baseUrl: string
- Die URL vom Resource Server
- Initialisierung der Abhängigkeiten im Konstruktur
- httpClient: HttpClient
- Implementierung der Methode requestSecuredResource()
- Via httpClient wird ein GET HTTP Request implementiert
- Datenmodel der erwarteten Antwort
DoubleSlash
- URL: baseURL + /secured
- Ruft die gesicherte API auf
- Datenmodel der erwarteten Antwort
- Via httpClient wird ein GET HTTP Request implementiert
- Implementierung der Methode requestUnsecuredResource()
- Via httpClient wird ein GET HTTP Request implementiert
- Datenmodel der erwarteten Antwort
DoubleSlash
- URL: baseURL + /unsecured
- Ruft die ungesicherte API auf
- Datenmodel der erwarteten Antwort
- Via httpClient wird ein GET HTTP Request implementiert
- Definition der Klassenvariable
Authentifizierung & Schnittstellen implementieren
- Öffnen von
src/app/app.component.ts
- Definition der Klassenvariablen
- securedContent: string
- unsecuredContent: string
- securedApiService: SecuredApiService
- oauthService: OAuthService
- authConfig: AuthConfig
- Enthält den Issuer -> Keycloak URL
- redirectUri -> Wohin wir nach erfolgreichem Login geleitet werden sollen (unser Angular Client)
- clientId -> Den von uns definierten Client in Keycloak
- scope -> Welche Informationen sollen im Token enthalten sein
- responseType -> Code
- showDebugInformation -> true
- Initialisierung der Abhängigkeiten im Konstruktor
- Aufruf der Methode configureOidClient()
- Diese wird nachfolgende implementiert
- Aufruf der Methode configureOidClient()
- Implementierung der Methode configureOidClient()
- Initialisiert wird zuerst die authConfig, welche in den Klassenvariablen definiert wurde.
- Anschließend wird das DiscoveryDocument geladen und ein Login versucht (für den Benutzer nicht sichtbar)
- Implementierung der Methode login()
- Nutzt die OAuthService Library für den Login.
- Sollte der Benutzer kein gültiges Token haben, wird er auf die Keycloak Login Seite weitergeleitet (Definiert in Issuer)
- Nach erfolgreichem Login wird der Benutzer auf die redirectUri weitergeleitet, welche unserer Client Anwendung entspricht
- Nutzt die OAuthService Library für den Login.
- Implementierung der Methode logout()
- Nutzt die OAuthService Library für den Logout.
- Token wird terminiert und ist nicht mehr gültig
- Nutzt die OAuthService Library für den Logout.
- Implementierung der Methode requestAPIs()
- Ruft die zuvor implementierten Services auf um die Schnittstelle aufzurufen und die Antwort in die zwei Klassenvariablen zu speichern.
- Da diese zwei Klassenvariablen im HTML Template via Binding integriert sind, sehen wir die Updates live
- Ruft die zuvor implementierten Services auf um die Schnittstelle aufzurufen und die Antwort in die zwei Klassenvariablen zu speichern.
- Definition der Klassenvariablen
Implementierung des HTML Templates
- Öffnen von
src/app/app.component.html
- Implementierung der zwei Klassenvariablen via Two-Way Binding (wird direkt aktualisiert)
- Diese Variablen zeigen die Antwort der zwei API anfragen
- Implementierung von drei Buttons
- Login -> ruft die Login Methode auf
- Logout -> ruft die Logout Methode auf
- Request APIs -> ruft die requestAPIs Methode auf
Starten des Clients
Nun muss die Anwendung noch gestartet werden.
ng serve
- Die Anwendung sollte nun unter http://localhost:4200 im Browser erreichbar sein
Klick auf Request APIs
- Ergebnis
- Beide APIs werden aufgerufen, die Secured API gibt einen 401 zurück und somit werden die geschützten Inhalte nicht dargestellt. Die ungeschützte API wird dargestellt.
Klick auf Login
- Ergebnis
- Keycloak öffnet sich
- Anmelden mit den Credentials die zuvor in Keycloak definiert wurden
- client-user / test
- Klick auf Login
- Ergebnis
- Keycloak leitet uns weiter an die Client App
- Ergebnis
Klick auf Request APIs
- Ergebnis
- Der geschützte Inhalt wird nun dargestellt, da das Token von Keycloak an die Anfrage angehängt wird.
Zusammenfassung
Dieser Beitrag zeigt die Integration des Angular Clients in eine bestehende OAuth2.0 Architektur. Die geringen Abhängigkeiten ermöglichen mit wenig Code sehr viel Funktionalitäten bereitzustellen. Die Loginseite von Keycloak lässt sich vollständig anpassen, so besteht die Möglichkeit die User Experience durch ein einheitliches Design deutlich zu steigern. Der produktive Einsatz des Clients wäre mit geringfügigen Anpassungen möglich. Dazu zählen unter anderem Funktionalitäten wie das Token auszulesen. Damit würde sichergestellt werden, dass Anfragen die ungültig sein würden, bereits vorher besser behandelt werden können, indem zum Beispiel ein Knopf disabled wird oder im Hintergrund ein Login durchgeführt wird.
Github
Zum Keycloak Server & Spring Boot Resource Server
Weitere Interessante Links und Quellen zum Thema
Die Rollverteilung im OAuth 2.0 Standard verstehen und Vorstellung des Implizit Flow
https://ordina-jworks.github.io/security/2019/08/22/Securing-Web-Applications-With-Keycloak.html#/