Authentifizierung zu deiner Angular-Anwendung hinzufügen
- Die folgende Demonstration basiert auf Angular 18.0.0 und angular-auth-oidc-client.
- Das Beispielprojekt ist im GitHub-Repository verfügbar.
Voraussetzungen
- Ein Logto Cloud Konto oder ein selbst gehostetes Logto.
- Eine Logto Single-Page-Anwendung erstellt.
Installation
Installiere Logto JS Core SDK und die Angular OIDC Client-Bibliothek:
- npm
- pnpm
- yarn
npm i @logto/js angular-auth-oidc-client
pnpm add @logto/js angular-auth-oidc-client
yarn add @logto/js angular-auth-oidc-client
Integration
Anwendung konfigurieren
Füge in deinem Angular-Projekt den Auth-Provider in deiner app.config.ts
hinzu:
import { buildAngularAuthConfig } from '@logto/js';
import { provideAuth } from 'angular-auth-oidc-client';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(withFetch()),
provideAuth({
config: buildAngularAuthConfig({
endpoint: '<your-logto-endpoint>',
appId: '<your-app-id>',
redirectUri: 'http://localhost:3000/callback',
postLogoutRedirectUri: 'http://localhost:3000/',
}),
}),
// ...andere Provider
],
};
Redirect-URIs konfigurieren
Bevor wir in die Details eintauchen, hier ein kurzer Überblick über die Endbenutzererfahrung. Der Anmeldeprozess kann wie folgt vereinfacht werden:
- Deine App ruft die Anmeldemethode auf.
- Der Benutzer wird zur Logto-Anmeldeseite umgeleitet. Bei nativen Apps wird der Systembrowser geöffnet.
- Der Benutzer meldet sich an und wird zurück zu deiner App umgeleitet (konfiguriert als die Redirect-URI).
Bezüglich der umleitungsbasierten Anmeldung
- Dieser Authentifizierungsprozess folgt dem OpenID Connect (OIDC) Protokoll, und Logto erzwingt strenge Sicherheitsmaßnahmen, um die Benutzeranmeldung zu schützen.
- Wenn du mehrere Apps hast, kannst du denselben Identitätsanbieter (Logto) verwenden. Sobald sich der Benutzer bei einer App anmeldet, wird Logto den Anmeldeprozess automatisch abschließen, wenn der Benutzer auf eine andere App zugreift.
Um mehr über die Gründe und Vorteile der umleitungsbasierten Anmeldung zu erfahren, siehe Logto-Anmeldeerfahrung erklärt.
In den folgenden Code-Snippets gehen wir davon aus, dass deine App unter http://localhost:3000/
läuft.
Redirect-URIs konfigurieren
Wechsle zur Anwendungsdetailseite der Logto-Konsole. Füge eine Redirect-URI http://localhost:3000/callback
hinzu.
Genau wie beim Anmelden sollten Benutzer zu Logto weitergeleitet werden, um sich von der gemeinsamen Sitzung abzumelden. Sobald dies abgeschlossen ist, wäre es ideal, den Benutzer zurück zu deiner Website zu leiten. Füge zum Beispiel http://localhost:3000/
als Redirect-URI nach dem Abmelden hinzu.
Klicke dann auf "Speichern", um die Änderungen zu speichern.
Redirect behandeln
Da wir http://localhost:3000/callback
als Redirect-URI verwenden, müssen wir sie nun ordnungsgemäß behandeln. Die Bibliothek angular-auth-oidc-client
bietet integrierte Unterstützung für die Behandlung des Redirects. Du kannst einfach die Auth-Provider-Konfigurationen richtig einstellen und die Bibliothek übernimmt den Rest.
export const appConfig: ApplicationConfig = {
providers: [
provideAuth({
config: buildAngularAuthConfig({
// ...andere Konfigurationen
redirectUri: 'http://localhost:3000/callback',
postLogoutRedirectUri: 'http://localhost:3000/',
}),
}),
// ...andere Provider
],
};
Anmeldung und Abmeldung implementieren
In der Komponente, in der du die Anmeldung und Abmeldung implementieren möchtest (zum Beispiel app.component.ts
), injiziere den OidcSecurityService
und verwende ihn, um sich anzumelden und abzumelden.
import { OidcSecurityService } from 'angular-auth-oidc-client';
export class AppComponent implements OnInit {
constructor(public oidcSecurityService: OidcSecurityService) {}
signIn() {
this.oidcSecurityService.authorize();
}
signOut() {
this.oidcSecurityService.logoff().subscribe((result) => {
console.log('app sign-out', result);
});
}
}
Füge dann im Template Buttons zum Anmelden und Abmelden hinzu:
<button (click)="signIn()">Anmelden</button>
<br />
<button (click)="signOut()">Abmelden</button>
Das Aufrufen von .signOut()
wird alle Logto-Daten im Speicher und im localStorage löschen, falls sie vorhanden sind.
Checkpoint: Teste deine Anwendung
Jetzt kannst du deine Anwendung testen:
- Starte deine Anwendung, du wirst den Anmeldebutton sehen.
- Klicke auf den Anmeldebutton, das SDK wird den Anmeldeprozess initiieren und dich zur Logto-Anmeldeseite weiterleiten.
- Nachdem du dich angemeldet hast, wirst du zurück zu deiner Anwendung geleitet und siehst den Abmeldebutton.
- Klicke auf den Abmeldebutton, um den lokalen Speicher zu leeren und dich abzumelden.
Benutzerinformationen abrufen
Sobald sich der Benutzer erfolgreich angemeldet hat, wird Logto ein ID-Token ausstellen, das die Benutzerinformationsansprüche enthält. Das ID-Token ist ein JSON Web Token (JWT).
Es ist wichtig zu beachten, dass die Benutzerinformationsansprüche, die abgerufen werden können, von den Berechtigungen abhängen, die der Benutzer während der Anmeldung verwendet hat. In Anbetracht der Leistung und der Datengröße kann das ID-Token möglicherweise nicht alle Benutzeransprüche enthalten; einige Benutzeransprüche sind nur im userinfo endpoint verfügbar (siehe die untenstehende Liste).
Das buildAngularAuthConfig()
-Utility aktiviert autoUserInfo
und renewUserInfoAfterTokenRenew
, wenn keine resource
in der Konfiguration angegeben ist. Das bedeutet, dass Logto automatisch die Benutzerinformationen abruft, nachdem sich der Benutzer angemeldet hat, und die Benutzerinformationen erneuert, nachdem das Token erneuert wurde.
Um mehr über die Konfiguration der angular-auth-oidc-client
-Bibliothek zu erfahren, siehe die offizielle Dokumentation.
Benutzerinformationen anzeigen
Der OidcSecurityService
bietet eine bequeme Möglichkeit, den Authentifizierungsstatus sowie die Benutzerinformationen zu abonnieren:
import { OidcSecurityService } from 'angular-auth-oidc-client';
import { decodeIdToken, type IdTokenClaims } from '@logto/js';
export class AppComponent implements OnInit {
isAuthenticated = false;
idTokenClaims?: IdTokenClaims;
accessToken?: string;
constructor(public oidcSecurityService: OidcSecurityService) {}
ngOnInit() {
this.oidcSecurityService.checkAuth().subscribe(({ isAuthenticated, idToken, accessToken }) => {
console.log('app authenticated', isAuthenticated, idToken);
this.isAuthenticated = isAuthenticated;
this.idTokenClaims = decodeIdToken(idToken);
this.accessToken = accessToken;
});
}
// ...andere Methoden
}
Und im Template verwenden:
<button *ngIf="!isAuthenticated" (click)="signIn()">Anmelden</button>
<ng-container *ngIf="isAuthenticated">
<pre>{{ idTokenClaims | json }}</pre>
<p>Zugangstoken: {{ accessToken }}</p>
<!-- ... -->
<button (click)="signOut()">Abmelden</button>
</ng-container>
Zusätzliche Ansprüche anfordern
Möglicherweise fehlen einige Benutzerinformationen im zurückgegebenen Objekt von idToken
. Dies liegt daran, dass OAuth 2.0 und OpenID Connect (OIDC) so konzipiert sind, dass sie dem Prinzip der minimalen Rechte (PoLP) folgen, und Logto auf diesen Standards basiert.
Standardmäßig werden begrenzte Ansprüche zurückgegeben. Wenn du mehr Informationen benötigst, kannst du zusätzliche Berechtigungen anfordern, um auf mehr Ansprüche zuzugreifen.
Ein "Anspruch (Claim)" ist eine Behauptung über ein Subjekt; eine "Berechtigung (Scope)" ist eine Gruppe von Ansprüchen. Im aktuellen Fall ist ein Anspruch ein Informationsstück über den Benutzer.
Hier ist ein nicht-normatives Beispiel für die Beziehung zwischen Berechtigung und Anspruch:
Der "sub"-Anspruch bedeutet "Subjekt", was der eindeutige Identifikator des Benutzers ist (d. h. Benutzer-ID).
Das Logto SDK wird immer drei Berechtigungen anfordern: openid
, profile
und offline_access
.
Um zusätzliche Berechtigungen anzufordern, kannst du die Auth-Provider-Konfigurationen anpassen:
import { UserScope, buildAngularAuthConfig } from '@logto/js';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(withFetch()),
provideAuth({
config: buildAngularAuthConfig({
// ...andere Konfigurationen
scopes: [
UserScope.Email,
UserScope.Phone,
UserScope.CustomData,
UserScope.Identities,
UserScope.Organizations,
],
}),
}),
// ...andere Provider
],
};
Dann kannst du auf die zusätzlichen Ansprüche im Rückgabewert von idToken
zugreifen.
Ansprüche, die Netzwerk-Anfragen benötigen
Um das ID-Token nicht aufzublähen, erfordern einige Ansprüche Netzwerk-Anfragen, um abgerufen zu werden. Zum Beispiel ist der custom_data
Anspruch nicht im Benutzerobjekt enthalten, selbst wenn er in den Berechtigungen angefordert wird. Um auf diese Ansprüche zuzugreifen, kannst du die userData
Option konfigurieren:
import { OidcSecurityService } from 'angular-auth-oidc-client';
import { type UserInfoResponse } from '@logto/js';
export class AppComponent implements OnInit {
isAuthenticated = false;
userData?: UserInfoResponse;
accessToken?: string;
constructor(public oidcSecurityService: OidcSecurityService) {}
ngOnInit() {
this.oidcSecurityService
.checkAuth()
.subscribe(({ isAuthenticated, userData, accessToken }) => {
console.log('app authenticated', isAuthenticated, idToken);
this.isAuthenticated = isAuthenticated;
this.userData = userData;
this.accessToken = accessToken;
});
}
// ...andere Methoden
}
// Jetzt kannst du auf den Anspruch `userData.custom_data` zugreifen
userData
wird das SDK die Benutzerinformationen abrufen, indem es eine Anfrage an den Userinfo-Endpunkt stellt, nachdem der Benutzer angemeldet ist, und userData
wird verfügbar sein, sobald die Anfrage abgeschlossen ist.
Berechtigungen und Ansprüche
Logto verwendet OIDC Berechtigungen und Ansprüche Konventionen, um die Berechtigungen und Ansprüche für das Abrufen von Benutzerinformationen aus dem ID-Token und dem OIDC userinfo endpoint zu definieren. Sowohl "Berechtigung (Scope)" als auch "Anspruch (Claim)" sind Begriffe aus den OAuth 2.0 und OpenID Connect (OIDC) Spezifikationen.
Hier ist die Liste der unterstützten Berechtigungen (Scopes) und der entsprechenden Ansprüche (Claims):
openid
Anspruchsname | Typ | Beschreibung | Benötigt userinfo? |
---|---|---|---|
sub | string | Der eindeutige Identifikator des Benutzers | Nein |
profile
Anspruchsname | Typ | Beschreibung | Benötigt userinfo? |
---|---|---|---|
name | string | Der vollständige Name des Benutzers | Nein |
username | string | Der Benutzername des Benutzers | Nein |
picture | string | URL des Profilbildes des Endbenutzers. Diese URL MUSS auf eine Bilddatei (zum Beispiel eine PNG-, JPEG- oder GIF-Bilddatei) verweisen und nicht auf eine Webseite, die ein Bild enthält. Beachte, dass diese URL speziell auf ein Profilfoto des Endbenutzers verweisen SOLLTE, das geeignet ist, den Endbenutzer zu beschreiben, und nicht auf ein beliebiges Foto, das vom Endbenutzer aufgenommen wurde. | Nein |
created_at | number | Zeitpunkt, zu dem der Endbenutzer erstellt wurde. Die Zeit wird als Anzahl der Millisekunden seit der Unix-Epoche (1970-01-01T00:00:00Z) dargestellt. | Nein |
updated_at | number | Zeitpunkt, zu dem die Informationen des Endbenutzers zuletzt aktualisiert wurden. Die Zeit wird als Anzahl der Millisekunden seit der Unix-Epoche (1970-01-01T00:00:00Z) dargestellt. | Nein |
Andere Standardansprüche wie family_name
, given_name
, middle_name
, nickname
, preferred_username
, profile
, website
, gender
, birthdate
, zoneinfo
und locale
werden ebenfalls im profile
-Scope enthalten sein, ohne dass der userinfo-Endpunkt angefordert werden muss. Ein Unterschied im Vergleich zu den oben genannten Ansprüchen besteht darin, dass diese Ansprüche nur zurückgegeben werden, wenn ihre Werte nicht leer sind, während die oben genannten Ansprüche null
zurückgeben, wenn die Werte leer sind.
Im Gegensatz zu den Standardansprüchen verwenden die Ansprüche created_at
und updated_at
Millisekunden anstelle von Sekunden.
email
Anspruchsname | Typ | Beschreibung | Benötigt userinfo? |
---|---|---|---|
string | Die E-Mail-Adresse des Benutzers | Nein | |
email_verified | boolean | Ob die E-Mail-Adresse verifiziert wurde | Nein |
phone
Anspruchsname | Typ | Beschreibung | Benötigt userinfo? |
---|---|---|---|
phone_number | string | Die Telefonnummer des Benutzers | Nein |
phone_number_verified | boolean | Ob die Telefonnummer verifiziert wurde | Nein |
address
Bitte siehe OpenID Connect Core 1.0 für die Details des Adressanspruchs.
custom_data
Anspruchsname | Typ | Beschreibung | Benötigt userinfo? |
---|---|---|---|
custom_data | object | Die benutzerdefinierten Daten des Benutzers | Ja |
identities
Anspruchsname | Typ | Beschreibung | Benötigt userinfo? |
---|---|---|---|
identities | object | Die verknüpften Identitäten des Benutzers | Ja |
sso_identities | array | Die verknüpften SSO-Identitäten des Benutzers | Ja |
urn:logto:scope:organizations
Anspruchsname | Typ | Beschreibung | Benötigt userinfo? |
---|---|---|---|
organizations | string[] | Die Organisations-IDs, denen der Benutzer angehört | Nein |
organization_data | object[] | Die Organisationsdaten, denen der Benutzer angehört | Ja |
urn:logto:scope:organization_roles
Anspruchsname | Typ | Beschreibung | Benötigt userinfo? |
---|---|---|---|
organization_roles | string[] | Die Organisationsrollen, denen der Benutzer angehört, im Format <organization_id>:<role_name> | Nein |
In Anbetracht der Leistung und der Datengröße bedeutet "Benötigt userinfo?" "Ja", dass der Anspruch nicht im ID-Token angezeigt wird, sondern in der Antwort des userinfo-Endpunkts zurückgegeben wird.
API-Ressourcen
Konfiguration von angular-auth-oidc-client
für API-Ressource
Wir empfehlen, zuerst 🔐 Rollenbasierte Zugangskontrolle (RBAC) zu lesen, um die grundlegenden Konzepte von Logto RBAC zu verstehen und wie man API-Ressourcen richtig einrichtet.
Sobald du die API-Ressourcen eingerichtet hast, kannst du sie bei der Konfiguration von Logto in deiner App hinzufügen:
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(withFetch()),
provideAuth({
config: buildAngularAuthConfig({
// ...other config
resource: 'https://your-api-resource.com',
}),
}),
// ...other providers
],
};
Jede API-Ressource hat ihre eigenen Berechtigungen (Berechtigungen).
Zum Beispiel hat die Ressource https://shopping.your-app.com/api
die Berechtigungen shopping:read
und shopping:write
, und die Ressource https://store.your-app.com/api
hat die Berechtigungen store:read
und store:write
.
Um diese Berechtigungen anzufordern, kannst du sie bei der Konfiguration von Logto in deiner App hinzufügen:
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(withFetch()),
provideAuth({
config: buildAngularAuthConfig({
// ...other config
resource: 'https://your-api-resource.com',
scopes: ['openid', 'profile', 'offline_access', 'read', 'write'],
}),
}),
// ...other providers
],
};
Du wirst bemerken, dass Berechtigungen separat von API-Ressourcen definiert sind. Dies liegt daran, dass Resource Indicators for OAuth 2.0 spezifiziert, dass die endgültigen Berechtigungen für die Anfrage das kartesische Produkt aller Berechtigungen bei allen Zielservices sein werden.
Es ist in Ordnung, Berechtigungen anzufordern, die in den API-Ressourcen nicht definiert sind. Zum Beispiel kannst du die Berechtigung email
anfordern, auch wenn die API-Ressourcen die Berechtigung email
nicht verfügbar haben. Nicht verfügbare Berechtigungen werden sicher ignoriert.
Nach der erfolgreichen Anmeldung wird Logto die entsprechenden Berechtigungen an API-Ressourcen gemäß den Rollen des Benutzers ausstellen.
Jetzt wird das Zugangstoken im JSON Web Token (JWT) Format anstelle eines zufälligen Strings (opakes Token) vorliegen.
Sowohl autoUserInfo
als auch renewUserInfoAfterTokenRenew
werden deaktiviert, wenn resource
gesetzt ist. Dies liegt daran, dass das Zugangstoken für die spezifische API-Ressource und nicht für den User-Info-Endpunkt angefordert wird.
Derzeit unterstützen nur die offiziellen Logto SDKs die Möglichkeit, sowohl Benutzerinformationen als auch Zugangstokens für API-Ressourcen anzufordern. Wenn du beides anfordern musst, zögere bitte nicht, uns zu kontaktieren.