Subject, Observable, Observer und Guards¶
Wir wollen am Beispiel einer Nutzerverwaltung die Verwendung von Subject, Observable, Observer und Guards demonstrieren. Alle diese Konzepte werden im Frontend verwendet. Subject, Observable, Observer dienen dazu, Werte an Subscriber zu propagieren. Eine gute Übersicht über Subject, Observable, Observer bietet die folgende Abbildung (hier entnommen).
Subject, Observable, Observer finden sich im RxJS-Paket. Subject hat den großen Vorteil, dass ein (neuer) Wert an viele Subscriber gesendet (multicast) werden kann. Wir werden Subjects z.B. verwenden, um der nav
-Komponente mitzuteilen, dass sich eine Nutzerin ein- bzw. ausgelogged hat. Ein Subject ist sowohl ein Observer als auch ein Observable. Observable kann mehrere Werte (nacheinander) pushen (an die Subscriber). Folgende Tabelle aus gibt einen guten Überblick über die Funktionalität eines *Observable*s.
Ein Observer konsumiert die Werte, die ein Observable liefert. Alle Funktionen des HTTP-Clients sind Observables. Sie liefern die Werte vom Backend (mittels einer next
-Funktion). Mithilfe eines Observers werden wir diese Werte empfangen (next
, error
, complete
).
Mithilfe von Guards wird die Verwendung von Komponenten gesteuert. Eine Komponente soll z.B. nur dann aufgerufen werden können, wenn die Nutzerin eingelogged ist.
Obwohl alle diese Konzepte zum Frontend gehören, erstellen wir uns zunächst ein Backend für die Nutzerverwaltung.
REST-API zur Nutzerverwaltung (Backend)¶
Folgende Endpunkte soll die REST-API zur Verfügung stellen:
Endpunkt | Beschreibung |
---|---|
GET /users |
gebe alle user -Einträge zurück |
POST /users/register |
erstelle einen neuen user (Registrierung -Funktion) |
POST /users/login |
Prüft, ob username == name existiert und ob das Passwort stimmt (Login -Funktion) |
GET /users/:name |
gibt den user mit username == name zurück |
DELETE /users/:id |
löscht den user mit _id == id |
PUT /users/:id |
ändert Daten von user mit _id == id |
Wir gehen wie in REST-API (MongoDB) vor und erstellen uns ein Node.js
-Projekt:
mkdir backend
cd backend
npm i
npm i express --save
npm i nodemon --save-dev
npm i mongoose --save
npm i dotenv --save
npm i cors --save
Als Einstiegspunkt wählen wir server.js
. Diese sieht wie folgt aus:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
Die Verbindungsdaten zur MongoDB stehen in der .env
-Datei unter DB_CONNECTION
und der Name der Datenbank steht dort unter DB_NAME
(siehe Zeile 15
). Für die Endpunkte (Routen) haben wir einen Ordner routes
erstellt, unter dem verschiedene .js
-Dateien liegen können, in denen unterschiedliche Endpunkte definiert sind. Hier wird zunächst nur die users.js
dort erstellt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
In der routes/users.js
sind zunächst nur die beiden Endpunkte GET /users
und POST /users
definiert. Wir wollen uns gleich um den Endpunkt POST /users
nochmal gesondert kümmern. Derzeit ist er so implementiert, wie wir es auch bereits in REST-API (MongoDB) hatten. Ehe wir diese Implementierung nochmal genauer betrachten zunächst noch das zugehörige Model:
1 2 3 4 5 6 7 8 9 10 |
|
Das Backend ist nun ausführbar. Es können neue user
angelegt werden (POST /users
) und alle user
ausgelesen werden (GET /users
).
Jedoch erkennen wir nun ein wesentliches Problem: die Passwörter werden lesbar gespeichert. Das wollen wir natürlich nicht.
Passwörter verschlüsseln¶
Wir verschlüsseln die Passwörter mithilfe von bcrypt. Dazu installieren wir uns dieses Paket zunächst
npm i bcrypt --save
und verwenden es dann wie folgt in der routes/users.js
für den POST /users
-Endpunkt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
In Zeile 15
wird die hash
-Funktion von bcrypt
aufgerufen. Das password
wird als erster Parameter übergeben. Die 10
ist der Wert für die saltRounds
und ist der empfohlene Wert. Der hash
wird erzeugt und als Wert der password
-Eigenschaft in newUser
und somit in der Datenbank gespeichert.
Es bleibt anzumerken, dass aus dem hash
nicht wieder das Passwort rückerzeugt werden kann. Um sich einzuloggen, muss das einegebene Passwort mit dem hash
verglichen werden. Dazu stellt bcrypt
ebenfalls eine Funktion zur Verfügung. Wir kommen darauf zurück, wenn es um die Login
-Funktion geht.
Zunächst wollen wir noch verhindern, dass sich eine Nutzerin mit einem bereits bekannten username
bzw. mit einer bereits bekannten email
-Adresse anmeldet.
Doppelte username
und email
verhindern¶
Doppelte Einträge in der user
-Datenbank für username
und/oder email
führen zu Problemen und sollten vermieden werden. Wir passen deshalb die Funktion für das Eintragen eines neuen Datensatzes wie folgt an:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
|
Es wird mithilfe von findOne()
nach einem Eintrag gesucht, der den neuen username
bzw. die neue email
enthält. Wenn kein solcher Eintrag gefunden wird, ist sowohl existingUsername
als auch existingEmail
null
und der neue Eintrag kann erzeugt werden. Ansonsten wird der HTTP-Status 400
mit der error
-Meldung username and/or email exist(s)
zurückgesendet. So wird sichergestellt, dass kein neuer user
erstellt wird, deren username
und/oder email
bereits in der Datenbank existiert.
Login
-Funktion¶
Eine Login
-Funktion soll überprüfen, ob ein username
existiert und ob das dazugehörige password
korrekt ist. Dazu müssen beide Informationen mit dem Request übermittelt werden. Deshalb wird als Anfragemethode POST
verwendet. Um diesen POST
-Endpunkt vom vorherigen Endpunkt zu unterscheiden, wird der URL anstelle von /register
hier /login
angehängt.
Die Implementierung dieser Funktion in der routes/users.js
könnte wie folgt aussehen:
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
|
Es wird zunächst geprüft, ob es überhaupt einen passenden username
in der Datenbank gibt. Da username
nicht doppelt vorkommen kann, muss auch nur findOne()
verwendet werden. Existiert ein solcher EIntrag nicht, wird HTTP-Status 400
zurückgesendet mit der error
-Message username does not exist
.
Existiert ein solcher Eintrag jedoch, wird das password
dieses Eintrages mit dem password
aus dem Request unter Verwendung der compare
-Funktion von bcrypt
miteinander verglichen. Sind die Passwärter gleich ist das result == true
. Dann wird der Status-Code 201
zusammen mit der message: logged in
gesendet. Ist jedoch result == false
, dann war das Passwort falsch und es wird der Statuscode 204
(no content
) zurückgesendet.
Daten ändern¶
Für das Ändern der Daten haben wir bereits die Standardfunktion betrachtet, siehe U - update. Bei der Nutzerverwaltung kommt jedoch die Anforderung hinzu, dass das Ändern der Daten (selbst das Ändern des Passwortes) nur dann möglich sein soll, wenn das (alte) Passwort korrekt übermittelt wird.
Sollte ein neues Passwort übermittelt werden (Eigenschaft newPassoword
), kann vorher im Frontend geprüft werden (z.B. durch doppelte Eingabe), ob es "korrekt" ist.
Es ist fraglich, ob es überhaupt möglich sein soll, den username
zu ändern. Generell ist jedoch beim Ändern des username
und beim Ändern der email
darauf zu achten, dass die jeweils neuen Werte nicht bereits existieren.
Zu beachten ist auch, dass der Endpunkt die _id
enthält. Das bedeutet, dass der Datensatz zuvor aus der Datenbank ausgelesen werden musste, d.h. er muss zwingend bereits existieren. Nur die Angabe von z.B. username
würde die Sicherheit reduzieren.
Die Funktion ist somit recht komplex und könnte z.B. wie folgt aussehen:
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
|
- Zunächst wird geprüft, ob überhaupt ein
user
mit der aufgerufenenid
existiert und ob daspassword
mitgeschickt wird (Zeile55
). Nur dann wird überhaupt weitergeprüft. Ansonsten werden die Zeilen94-96
ausgeführt (HTTP-Status204
gesendet). - In Zeile
56
wird geprüft, ob das mitgeschicktepassword
dem füruser
gespeichertenpassword
entspricht. Das geschieht mithilfe dercompare()
-Funktion vonbcrypt
. Ist daspassword
nicht korrekt, werden die Zeilen89-91
ausgeführt (HTTP-Status204
gesendet). - Ist das
password
korrekt, wird geprüft, welche der Daten geändert werden sollen. Dazu wird jeweils geschaut, obnewPassword
(Zeilen61-69
),username
(Zeilen71-75
),email
(Zeilen77-81
) oderrole
(Zeilen83-85
) mitgesendet werden. Falls ja, wird jeweils der Datensatz mithilfe vonupdateOne()
aktualisiert.
user
löschen und lesen¶
Die beiden Funktionen zum Löschen und Lesen einer Nutzerin sind so, wie wir sie bereits kennen:
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
|
Registrierung und Login (Frontend)¶
Wir erstellen uns mithilfe von Angular eine kleine Webanwendung, die mindestens eine Regstrierungs- und eine Login-Komponente enthält. Wir wollen dieses Mal Material Design anstelle von Bootstrap als CSS-Framework verwenden.
Im Terminal geben wir Folgendes ein:
Terminalbefehl | Beschreibung |
---|---|
ng new frontend --routing |
erstellt Projekt frontend mit Routing |
cd frontend |
|
ng g c login |
erstellt Komponente login |
ng g c home |
erstellt Komponente home |
ng g s shared/auth |
erstellt Service auth im Ordner shared |
ng g i shared/user |
erstellt Interface user im Ordner shared |
ng add @angular/material |
fügt Material Design hinzu |
Nach dem Hinzufügen von Material Design sollte im Terminal ungefähr folgende Ausgabe erscheinen:
ℹ Using package manager: npm
✔ Found compatible package version: @angular/material@15.0.4.
✔ Package information loaded.
The package @angular/material@15.0.4 will be installed and executed.
Would you like to proceed? Yes
✔ Packages successfully installed.
? Choose a prebuilt theme name, or "custom" for a custom theme: Indigo/Pink [ Preview:
https://material.angular.io?theme=indigo-pink ]
? Set up global Angular Material typography styles? Yes
? Include the Angular animations module? Include and enable animations
UPDATE package.json (1105 bytes)
✔ Packages installed successfully.
UPDATE src/app/app.module.ts (654 bytes)
UPDATE angular.json (2844 bytes)
UPDATE src/index.html (576 bytes)
UPDATE src/styles.css (181 bytes)
Als prebuild theme
wurde hier Indigo/Pink
und sowohl für die typography styles
als auch für die animations
wurde y
ausgewählt.
Material Design bietet sogenannte Schematics an. Wir wählen das navigation
-Schema und geben im Terminal ein:
ng generate @angular/material:navigation nav
nav
-Komponente. Außerdem wählen wir das address-form
-Schema und erstellen damit eine Komponente register
:
ng generate @angular/material:address-form register
Die app.component.html
ändern wir wie folgt:
<app-nav></app-nav>
Darin wird also nur noch die nav
-Komponente statisch eingebunden.
Ehe wir an der nav.component.html
umfangreichere Änderungen vornehmen, defininieren wir zunächst noch folgende Routen:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
Nun können wir die nav.component.html
entsprechend anpassen:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
In den Zeilen 8-10
werden die Menüeinträge geändert und die Verweise auf routerLinks
geändert. In Zeile 23
wird die Überschrift geändert und in Zeile 26
erscheint der Platzhalter für die per Routing eingebundenen Komponenten.
Die Anwendung sieht nun wie folgt aus (Desktop- und Mobile-Ansicht):
Die Menüeinträge funktionieren und bei der register
-Komponente wird bereits ein recht umfangreiches Formular angezeigt (wegen des verwendeten address-form
-Schemas).
Registrierung¶
Wir passen die durch das address-form
-Schema erstellte register
-Komponente an. Die Dateien der register
-Komponente könnten z.B. so aussehen:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
Das ergibt folgende Ansicht:
Service verwenden¶
In dem auth
-Service binden wir das Backend an und nutzen bspw. die im Registrierungsformular eingegebenen Daten, um die Nutzerin zu registrieren.
Achtung!
Nicht vergessen, das HttpClientModule
in der app.module.ts
zu importieren (unter imports
eintragen und import { HttpClientModule } from '@angular/common/http';
einfügen lassen)!
Wichtig ist auch, dass das Backend läuft!
Der Service könnte z.B. so aussehen:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
und die submit()
-Funktion in der register.component.ts
könnte zunächst wie folgt erweitert werden:
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
|
Wenn nun das Registrierungsformular vollständig ausgefüllt wird und weder username
noch email
bereits in der Datenbank existieren, wird ein neuer Datensatz in der Datenbank angelegt. Die neue Nutzerin ist registriert. Wenn jedoch der username
und/oder die email
bereits existier(t/en), wird nicht die next
-Eigenschaft des Observers aufgerufen, sondern die error
-Eigenschaft. Das heißt, entweder gibt es unter next
eine response
, nämlich den neu angelegten user
oder es gibt unter error
ein Fehlerobjekt, welches selbst eine error
-Eigenschaft hat (mit { error: 'username and/or email exist(s)'}
) und dessen Status 400
ist.
Modaler Dialog zur Bestätigung¶
Derzeit gibt es keine Rückmeldung darüber, ob die neue Nutzerin registriert wurde oder nicht. Wir wollen dazu einen modalen Dialog öffnen, der die entsprechenden Informationen zur Verfügung stellt. Dieser Dialog wird eine Komponente. Da diese Komponente jedoch ausschließlich von der Registrierungskomponente verwendet wird, erstellen wir sie als Kindkomponente der Registrierungskomponente. Wir werden dabei insbesondere lernen, wie wir Daten von Elternkomponenten an Kindkomponenten weiterleiten können.
Zunächst erstellen wir die (Kind-)Komponente confirm
:
ng g c register/confirm
Unter dem Ordner register
entsteht ein weiterer Ordner confirm
, der die .html
, .ts
und .css
der Kindkomponente confirm
enthält. Wir verwenden Dialog von Material Design. Wir gehen vor, wie in Dialog Examples gezeigt. Beachten Sie, dass Sie in app.module.ts
das Modul MatDialogModule
(aus @angular/material/dialog
) importieren müssen!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
|
1 2 3 4 5 6 7 8 9 10 11 12 |
|
1 2 3 4 5 6 7 |
|
Wenn nun die Registrierung erfolgreich war, erscheint ein entsprechender modaler Dialog und ebenso, wenn die Registrierung nicht erfolgt ist:
Guards¶
Mithilfe von Guards können wir festlegen, dass Komponenten z.B. nur dann aufgerufen werden können, wenn man eingelogged ist (aber nicht, wenn man nicht eingelogged ist) oder wenn man z.B. als admin
eingelogged (und nicht nur als user
) eingelogged ist. Wir werden hier demonstrieren, wie man solche Guards implementiert und verwendet. Dazu erstellen wir uns zunächst eine weitere Komponente. Die Komponente userlist
soll alle user
aus der Datenbank auflisten (als Tabelle). Diese Komponente soll nur aufgerufen werden können, wenn man als admin
eingelogged ist. Außerdem werden wir den Aufruf der HomeComponent
nur für den Fall erlauben, dass man eingelogged ist.
userlist
-Komponente¶
Die userlist
-Komponente erstellen wir mithilfe des Material-Design-Schemas table:
ng generate @angular/material:table userlist
Für das vereinfachte Beispiel hier haben wir jedoch die z.B. die Paginierung weggelassen. Viele Beispiele zu Tabellen mit Sortierung, Filterung, Paginierung usw. finden Sie hier.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
Die Tabelle sieht dann wie folgt aus:
Guard für den Komponentenzugriff - Logged in¶
In Routen absichern mit Guards haben wir bereits die Grundidee von Guards vorgestellt. Wir wollen diese hier anwenden und beschränken uns dabei auf den Guard-Typ CanActivate
. Wir wollen sicherstellen, dass die HomeComponent
nur aktiviert werden kann, wenn man eingelogged ist und die RegisterComponent
nur dann, wenn man als admin
eingelogged ist, um das Prinzip zu verdeutlichen. Wir erstellen uns also einen CanActivate
-Guard (im Ordner guards
):
ng g guard shared/authguard --implements CanActivate
Diesen AuthGuard
implementieren wir wie folgt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
Dieser Guard gibt bei Aufruf der canActivate()
-Funktion ein true
zurück, wenn eine Nutzerin eingelogged ist (isLoggedin()
aus dem AuthService
). Wenn niemand eingelogged ist, (wenn also isLoggedin()
ein false
zurückgibt), dann wird die aktuelle Route nach /login
umgeleitet. Die Funktion isLoggedin()
sieht im auth.service.ts
wie folgt aus (außerdem erweitern wir den Service gleich noch um einige weitere nützliche Funktionen):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
|
Beachten Sie, dass der post()
-Funktion in loginUser()
noch die Option observe: 'response'
hinzugefügt wurde, um die gesamte Response zu erhalten und nicht nur den body
als json
. Das gibt uns die Möglichkeit, den status
der Response auszuwerten. Schauen Sie sich dazu auch den POST /users/login
-Endpunkt im Backend an. Der schickt verschiedene Status zurück, je nachdem, ob das Login erfolgreich war (201
) oder nicht (204
bzw. 400
).
In der RegisterComponent
können wir nun auch noch die login()
-Funktion des Services aufrufen, wenn die Registrierung erfolgreich war:
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
|
Wir fügen diesen Guard nun in die app-routing.module.ts
ein:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
|
Wenn wir nun die Anwendung öffnen, dann kommen wir gar nicht auf HomeComponent
, sondern werden stets zur LoginComponent
geleitet. Erst wenn wir eingelogged sind, ist die HomeComponent
erreichbar.
Login-Komponente¶
Ehe wir noch einen weiteren Guard zur Erkennung implementieren, ob wir als admin
eingelogged sind oder nicht, implementieren wir der Vollständigkeit halber noch die Login-Komponente.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
1 2 3 4 5 6 7 8 9 10 11 |
|
Das ergibt folgende Ansicht:
Wenn das Login erfolgreich war, wird direkt die home
-Komponente aufgerufen. Ist das Login nicht erfolgreich, wird bei der Login-Komponente verblieben. Es erfolgt nur eine Nachricht auf der Konsole - hier könnte (sollte!) natürlich auch ein modaler Dialog erscheinen, wie bei der Registrierung.
Guard für den Komponentenzugriff - admin
¶
Wir erstellen noch einen weiteren Guard, um auch abzuprüfen, ob wir als admin
eingelogged sind und wollen mit diesem Guard die UserlistComponent
sichern, d.h. diese Komponente soll nur aufgerufen werden dürfen, wenn die eingeloggte Nutzerin die Rolle admin
besitzt (nicht user
).
ng g guard shared/adminguard --implements CanActivate
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
Dieses Mal wird geprüft, ob die Nutzerin eingelogged und in der admin
-Rolle ist. Diesen Guard fügen wir der /users
-Route hinzu (also für die UserlistComponent)
. Nur ein admin
darf alle Nutzerinnen sehen (wird hier exemplarisch angenommen).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
|
Wenn nun eine admin
-Userin eingelogged ist, kann sie alle Komponenten öffnen. Ist eine user
-Userin eingelogged, hat sie keinen Zugriff auf die UserlistComponent
, aber auf alle anderen Komponenten. Ist niemand eingelogged, kann nur die Login
- und die RegisterComponent
verwendet werden.
Subjects für Login/Logout¶
Wir wollen in der nav
-Komponente ein Login-Icon eintegrieren, wenn keine Nutzerin eingelogged ist bzw. den Nutzernamen der eingeloggten Nutzerin. Die nav
-Komponente muss also darüber informiert werden, wenn sich eine Nutzerin einlogged bzw. auslogged. Dazu verwenden wir Subjects.
Wir erweitern dazu den AuthService
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
|
Wir haben nun Subjects, die darüber informieren (next()
), wenn sich ein bestimmter Wert ändert. In der NavComponent
melden wir uns an diese Subjects an (subscribe
):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
|
Die nav
-Komponente hat nun oben rechts ein Login-Icon (Button), wenn niemand eingelogged ist bzw. den username
und einen Logout-Icon (Button) der Nutzerin, die eingelogged ist. Mithilfe von Subject wird sofort darauf reagiert, wenn sich jemand ein- bzw. ausloggt.
Success
Wir haben eine (sehr einfache) Nutzerverwaltung implementiert. Eine Nutzerin kann sich registrieren und einloggen. Die Registrierungsdaten werden in der Datenbank gespeichert. Das Passwort wird verschlüsselt abgelegt. Jeder Nutzerin kann eine Rolle zugewiesen werden. Abhängig davon, ob jemand eingelogged ist bzw. in welcher Rolle, sind die Komponenten unterschiedlich erreichbar. Dies wurde mit Guards realisiert. Für das Layout wurde Angular Material verwendet. Die Nutzerverwaltung ist noch sehr rudimentär. Es fehlt z.B. noch das Ausloggen. Es wäre auch gut, wenn die Nutzerin nach misslungenem Einloggen eine entsprechende Nachricht bekäme. Die Konzepte für eine Dialoggestaltung, für die Erweitereung und Anbindung des Backends sowie für eine Weitereleitung auf eine andere Komponente wurden jedoch alle exemplarisch gezeigt.