Authentifizierung zu deiner .NET Core (Blazor WASM)-Anwendung hinzufügen
- Die folgende Demonstration basiert auf .NET Core 8.0 und Blorc.OpenIdConnect.
- Die .NET Core-Beispielprojekte sind im GitHub-Repository verfügbar.
Voraussetzungen
- Ein Logto Cloud-Konto oder ein selbst gehostetes Logto.
- Eine Logto Single Page Application erstellt.
Installation
Füge das NuGet-Paket zu deinem Projekt hinzu:
dotnet add package Blorc.OpenIdConnect
Integration
Skriptreferenzen hinzufügen
Füge Blorc.Core/injector.js
in die index.html
-Datei ein:
<head>
<!-- ... -->
<script src="_content/Blorc.Core/injector.js"></script>
<!-- ... -->
</head>
Dienste registrieren
Füge den folgenden Code zur Program.cs
-Datei hinzu:
using Blorc.OpenIdConnect;
using Blorc.Services;
builder.Services.AddBlorcCore();
builder.Services.AddAuthorizationCore();
builder.Services.AddBlorcOpenIdConnect(
options =>
{
builder.Configuration.Bind("IdentityServer", options);
});
var webAssemblyHost = builder.Build();
await webAssemblyHost
.ConfigureDocumentAsync(async documentService =>
{
await documentService.InjectBlorcCoreJsAsync();
await documentService.InjectOpenIdConnectAsync();
});
await webAssemblyHost.RunAsync();
Es ist nicht notwendig, das Microsoft.AspNetCore.Components.WebAssembly.Authentication
-Paket zu verwenden. Das Blorc.OpenIdConnect
-Paket übernimmt den Authentifizierungsprozess.
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.
Anwendung konfigurieren
Füge den folgenden Code zur appsettings.json
-Datei hinzu:
{
// ...
IdentityServer: {
Authority: 'https://<your-logto-endpoint>/oidc',
ClientId: '<your-logto-app-id>',
PostLogoutRedirectUri: 'http://localhost:3000/',
RedirectUri: 'http://localhost:3000/callback',
ResponseType: 'code',
Scope: 'openid profile', // Weitere Berechtigungen hinzufügen, falls erforderlich
},
}
Denke daran, die RedirectUri
und PostLogoutRedirectUri
zur Liste der erlaubten Redirect-URIs in den Logto-Anwendungseinstellungen hinzuzufügen. Beide sind die URL deiner WASM-Anwendung.
AuthorizeView
-Komponente hinzufügen
In den Razor-Seiten, die Authentifizierung erfordern, füge die AuthorizeView
-Komponente hinzu. Nehmen wir an, es ist die Home.razor
-Seite:
@using Microsoft.AspNetCore.Components.Authorization
@page "/"
<AuthorizeView>
<Authorized>
@* Angemeldete Ansicht *@
<button @onclick="OnLogoutButtonClickAsync">
Abmelden
</button>
</Authorized>
<NotAuthorized>
@* Nicht authentifizierte Ansicht *@
<button @onclick="OnLoginButtonClickAsync">
Anmelden
</button>
</NotAuthorized>
</AuthorizeView>
Authentifizierung einrichten
In der Home.razor.cs
-Datei (erstelle sie, falls sie nicht existiert), füge den folgenden Code hinzu:
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using Blorc.OpenIdConnect;
using Microsoft.AspNetCore.Components.Authorization;
[Authorize]
public partial class Home : ComponentBase
{
[Inject]
public required IUserManager UserManager { get; set; }
public User<Profile>? User { get; set; }
[CascadingParameter]
protected Task<AuthenticationState>? AuthenticationStateTask { get; set; }
protected override async Task OnInitializedAsync()
{
User = await UserManager.GetUserAsync<User<Profile>>(AuthenticationStateTask!);
}
private async Task OnLoginButtonClickAsync(MouseEventArgs obj)
{
await UserManager.SignInRedirectAsync();
}
private async Task OnLogoutButtonClickAsync(MouseEventArgs obj)
{
await UserManager.SignOutRedirectAsync();
}
}
Sobald der Benutzer authentifiziert ist, wird die User
-Eigenschaft mit den Benutzerinformationen gefüllt.
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
Benutzerinformationen anzeigen
Hier sind einige Beispiele, wie Benutzerinformationen auf der Seite Home.razor
angezeigt werden können:
<AuthorizeView>
<Authorized>
@* Angemeldete Ansicht *@
@* ... *@
<p>Sie sind angemeldet als @(@User?.Profile?.Name ?? "(unbekannter Name)").</p>
</Authorized>
@* ... *@
</AuthorizeView>
Für weitere Eigenschaften und Ansprüche, überprüfe die Klassen User
und Profile
im Paket Blorc.OpenIdConnect
.
Zusätzliche Ansprüche anfordern
Möglicherweise fehlen einige Benutzerinformationen im zurückgegebenen Objekt von User
. 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 gültige Berechtigungen zur Eigenschaft IdentityServer.Scope
in der Datei appsettings.json
hinzufügen.
{
// ...
"IdentityServer": {
// ...
"Scope": "openid profile email phone"
}
}
Ansprüche, die eine Netzwerkabfrage benötigen
Um das Benutzerobjekt nicht aufzublähen, erfordern einige Ansprüche Netzwerkabfragen, um abgerufen zu werden. Zum Beispiel ist der Anspruch custom_data nicht im Benutzerobjekt enthalten, selbst wenn er in den Berechtigungen angefordert wird. Um diese Ansprüche abzurufen, kannst du die Eigenschaft IdentityServer.LoadUserInfo
in der Datei appsettings.json
auf true
setzen.
Zum Beispiel, um die E-Mail-Adresse und die benutzerdefinierten Daten des Benutzers abzurufen, kannst du die folgende Konfiguration verwenden:
{
// ...
"IdentityServer": {
// ...
"Scope": "openid profile email custom_data",
"LoadUserInfo": true
}
}
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
Wir empfehlen, zuerst 🔐 Rollenbasierte Zugangskontrolle (RBAC) zu lesen, um die grundlegenden Konzepte von Logto RBAC zu verstehen und wie man API-Ressourcen richtig einrichtet.
Standardmäßig erhältst du, wenn du auf User?.AccessToken
zugreifst, ein opakes Token (Opaque token), das eine kurze Länge hat und kein JWT (JSON Web Token) ist. Dieses Token wird verwendet, um auf den userinfo-Endpunkt zuzugreifen.
API-Ressource zur Konfiguration hinzufügen
Um ein JWT-Token zu erhalten, das zum Zugriff auf eine in Logto definierte API-Ressource verwendet werden kann, füge die folgenden Parameter zur Datei appsettings.json
hinzu (unter Verwendung von https://my-api-resource
als Beispiel):
{
// ...
"IdentityServer": {
// ...
"Scope": "openid profile email <your-api-scopes>", // Füge hier deine API-Berechtigungen hinzu
"Resource": "https://my-api-resource",
"ExtraTokenParams": {
"resource": "https://my-api-resource" // Stelle sicher, dass der Schlüssel "resource" in Kleinbuchstaben ist
}
}
}
Die Resource
-Eigenschaft wird verwendet, um die API-Ressource zur Authentifizierungsanfrage hinzuzufügen. Die ExtraTokenParams
-Eigenschaft wird verwendet, um die API-Ressource zur Token-Anfrage hinzuzufügen. Da Logto RFC 8707 für API-Ressourcen einhält, sind beide Eigenschaften erforderlich.
Da WebAssembly eine clientseitige Anwendung ist, wird die Token-Anfrage nur einmal an die Serverseite gesendet. Aufgrund dieser Natur steht LoadUserInfo
im Konflikt mit dem Abrufen des Zugangstokens (Access token) für API-Ressourcen.
Zugangstoken verwenden
Sobald der Benutzer authentifiziert ist, kannst du auf die API-Ressource zugreifen, indem du die User?.AccessToken
-Eigenschaft verwendest. Zum Beispiel kannst du den HttpClient
verwenden, um auf die API-Ressource zuzugreifen:
using Blorc.OpenIdConnect;
builder.Services
.AddHttpClient("MyApiResource", client =>
{
client.BaseAddress = new Uri("https://my-api-resource");
})
.AddAccessToken(); // Zugangstoken zur Anforderungsüberschrift hinzufügen