Zum Hauptinhalt springen

Authentifizierung zu deiner iOS (Swift)-Anwendung hinzufügen

hinweis:

Diese Anleitung geht davon aus, dass du eine Anwendung des Typs "Native app" in der Admin-Konsole erstellt hast.

Installation

Verwende die folgende URL, um Logto SDK als Abhängigkeit im Swift Package Manager hinzuzufügen.

https://github.com/logto-io/swift.git

Seit Xcode 11 kannst du ein Swift-Paket direkt importieren ohne zusätzliche Tools.

Wir unterstützen derzeit Carthage und CocoaPods aufgrund einiger technischer Probleme nicht.

Carthage

Carthage benötigt eine xcodeproj-Datei zum Bauen, aber swift package generate-xcodeproj wird einen Fehler melden, da wir binäre Ziele für native soziale Plugins verwenden. Wir werden versuchen, später eine Lösung zu finden.

CocoaPods

CocoaPods unterstützt keine lokale Abhängigkeit und Monorepo, daher ist es schwierig, ein .podspec für dieses Repository zu erstellen.

Integration

Init LogtoClient

Initialisiere den Client, indem du eine LogtoClient-Instanz mit einem LogtoConfig-Objekt erstellst.

ContentView.swift
import Logto
import LogtoClient

let config = try? LogtoConfig(
endpoint: "<your-logto-endpoint>", // Z.B. http://localhost:3001
appId: "<your-app-id>"
)
let client = LogtoClient(useConfig: config)
info:

Standardmäßig speichern wir Anmeldeinformationen wie ID-Token und Auffrischungstoken im Schlüsselbund. Daher muss sich der Benutzer nicht erneut anmelden, wenn er zurückkehrt.

Um dieses Verhalten zu deaktivieren, setze usingPersistStorage auf false:

let config = try? LogtoConfig(
// ...
usingPersistStorage: false
)

Implementiere An- und Abmeldung

Bevor wir ins Detail gehen, hier ein schneller Überblick über die Endbenutzererfahrung. Der Anmeldeprozess lässt sich wie folgt vereinfachen:

  1. Deine App löst die Anmeldemethode aus.
  2. Der Benutzer wird auf die Logto-Anmeldeseite umgeleitet. Bei nativen Apps wird der Systembrowser geöffnet.
  3. Der Benutzer meldet sich an und wird zurück zu deiner App umgeleitet (konfiguriert als Redirect-URI).

Bezüglich der umleitungsbasierten Anmeldung

  1. Dieser Authentifizierungsprozess folgt dem OpenID Connect (OIDC) Protokoll, und Logto erzwingt strenge Sicherheitsmaßnahmen, um die Benutzeranmeldung zu schützen.
  2. 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.


Redirect-URI konfigurieren

Wechseln wir zur Seite "Anwendungsdetails" der Logto-Konsole. Füge eine Redirect-URI io.logto://callback hinzu und klicke auf "Änderungen speichern".

Redirect-URI in Logto-Konsole
info:

Die Redirect-URI im iOS SDK ist nur für den internen Gebrauch. Es besteht KEINE NOTWENDIGKEIT, ein Custom URL Scheme hinzuzufügen, bis ein Connector dies verlangt.

Anmelden und Abmelden

hinweis:

Bevor du .signInWithBrowser(redirectUri:) aufrufst, stelle sicher, dass du die Redirect-URI im Admin Console korrekt konfiguriert hast.

Du kannst client.signInWithBrowser(redirectUri:) verwenden, um den Benutzer anzumelden, und client.signOut(), um den Benutzer abzumelden.

Zum Beispiel in einer SwiftUI-App:

ContentView.swift
struct ContentView: View {
@State var isAuthenticated: Bool

init() {
isAuthenticated = client.isAuthenticated
}

var body: some View {
VStack {
if isAuthenticated {
Button("Abmelden") {
Task { [self] in
await client.signOut()
isAuthenticated = false
}
}
} else {
Button("Anmelden") {
Task { [self] in
do {
try await client.signInWithBrowser(redirectUri: "${
props.redirectUris[0] ?? 'io.logto://callback'
}")
isAuthenticated = true
} catch let error as LogtoClientErrors.SignIn {
// Fehler trat während der Anmeldung auf
} catch {
// andere Fehler
}
}
}
}
}
}
}

Checkpoint: Teste deine Anwendung

Jetzt kannst du deine Anwendung testen:

  1. Starte deine Anwendung, du wirst den Anmeldebutton sehen.
  2. Klicke auf den Anmeldebutton, das SDK wird den Anmeldeprozess initiieren und dich zur Logto-Anmeldeseite weiterleiten.
  3. Nachdem du dich angemeldet hast, wirst du zurück zu deiner Anwendung geleitet und siehst den Abmeldebutton.
  4. Klicke auf den Abmeldebutton, um den Token-Speicher zu leeren und dich abzumelden.

Benutzerinformationen abrufen

Benutzerinformationen anzeigen

Um die Informationen des Benutzers anzuzeigen, kannst du die Methode client.getIdTokenClaims() verwenden. Zum Beispiel in einer SwiftUI-App:

ContentView.swift
struct ContentView: View {
@State var isAuthenticated: Bool
@State var name: String?

init() {
isAuthenticated = client.isAuthenticated
name = try? client.getIdTokenClaims().name
}

var body: some View {
VStack {
if isAuthenticated {
Text("Willkommen, \(name)")
} else {
Text("Bitte anmelden")
}
}
}
}

Zusätzliche Ansprüche anfordern

Möglicherweise fehlen einige Benutzerinformationen im zurückgegebenen Objekt von client.getIdTokenClaims(). 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.

info:

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:

tipp:

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 Berechtigungen an das LogtoConfig-Objekt übergeben. Zum Beispiel:

ContentView.swift
let config = try? LogtoConfig(
endpoint: "<your-logto-endpoint>", // Z.B. http://localhost:3001
appId: "<your-app-id>",
scopes: [
UserScope.Email.rawValue,
UserScope.Phone.rawValue,
]
)

Dann kannst du auf die zusätzlichen Ansprüche im Rückgabewert von client.getIdTokenClaims() zugreifen:

let claims = try? client.getIdTokenClaims()
// Jetzt kannst du auf zusätzliche Ansprüche `claims.email`, `claims.phone` usw. 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 client.fetchUserInfo() Methode verwenden:

let userInfo = try? client.fetchUserInfo()
// Jetzt kannst du auf den Anspruch `userInfo.custom_data` zugreifen
Diese Methode wird die Benutzerinformationen abrufen, indem sie eine Anfrage an den Userinfo-Endpunkt stellt. Um mehr über die verfügbaren Berechtigungen und Ansprüche zu erfahren, siehe den Berechtigungen und Ansprüche Abschnitt.

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

Claim-NameTypBeschreibungBenötigt userinfo?
substringDer eindeutige Identifikator des BenutzersNein

profile

Claim-NameTypBeschreibungBenötigt userinfo?
namestringDer vollständige Name des BenutzersNein
usernamestringDer Benutzername des BenutzersNein
picturestringURL zum Profilbild des Endbenutzers. Diese URL MUSS auf eine Bilddatei (z. B. PNG, JPEG oder GIF) verweisen und nicht auf eine Webseite, die ein Bild enthält. Beachte, dass diese URL speziell auf ein Profilfoto des Endbenutzers verweisen SOLLTE, das sich zur Darstellung des Endbenutzers eignet, und nicht auf ein beliebiges vom Endbenutzer aufgenommenes Foto.Nein
created_atnumberZeitpunkt, 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_atnumberZeitpunkt, 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

Weitere 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 das Userinfo-Endpunkt abgefragt werden muss. Ein Unterschied 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.

hinweis:

Im Gegensatz zu den Standardansprüchen verwenden die Ansprüche created_at und updated_at Millisekunden anstelle von Sekunden.

email

Claim-NameTypBeschreibungBenötigt userinfo?
emailstringDie E-Mail-Adresse des BenutzersNein
email_verifiedbooleanOb die E-Mail-Adresse verifiziert wurdeNein

phone

Claim-NameTypBeschreibungBenötigt userinfo?
phone_numberstringDie Telefonnummer des BenutzersNein
phone_number_verifiedbooleanOb die Telefonnummer verifiziert wurdeNein

address

Bitte siehe OpenID Connect Core 1.0 für Details zum Address-Anspruch.

custom_data

Claim-NameTypBeschreibungBenötigt userinfo?
custom_dataobjectDie benutzerdefinierten DatenJa

identities

Claim-NameTypBeschreibungBenötigt userinfo?
identitiesobjectDie verknüpften Identitäten des BenutzersJa
sso_identitiesarrayDie verknüpften SSO-Identitäten des BenutzersJa

roles

Claim-NameTypBeschreibungBenötigt userinfo?
rolesstring[]Die Rollen des BenutzersNein

urn:logto:scope:organizations

Claim-NameTypBeschreibungBenötigt userinfo?
organizationsstring[]Die Organisations-IDs, denen der Benutzer angehörtNein
organization_dataobject[]Die Organisationsdaten, denen der Benutzer angehörtJa
hinweis:

Diese Organisationsansprüche können auch über das Userinfo-Endpunkt abgerufen werden, wenn ein Opaker Token verwendet wird. Allerdings können opake Tokens nicht als Organisationstoken für den Zugriff auf organisationsspezifische Ressourcen verwendet werden. Siehe Opaker Token und Organisationen für weitere Details.

urn:logto:scope:organization_roles

Claim-NameTypBeschreibungBenötigt userinfo?
organization_rolesstring[]Die Organisationsrollen des Benutzers im Format <organization_id>:<role_name>Nein

Im Hinblick auf Leistung und Datenmenge gilt: Wenn "Benötigt userinfo?" mit "Ja" angegeben ist, erscheint der Anspruch nicht im ID-Token, sondern wird in der Antwort des Userinfo-Endpunkts zurückgegeben.

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.

Logto-Client konfigurieren

Sobald du die API-Ressourcen eingerichtet hast, kannst du sie bei der Konfiguration von Logto in deiner App hinzufügen:

ContentView.swift
let config = try? LogtoConfig(
endpoint: "<your-logto-endpoint>", // Z.B. http://localhost:3001
appId: "<your-app-id>",
resources: ["https://shopping.your-app.com/api", "https://store.your-app.com/api"], // API-Ressourcen hinzufügen
)
let client = LogtoClient(useConfig: config)

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:

ContentView.swift
let config = try? LogtoConfig(
endpoint: "<your-logto-endpoint>",
appId: "<your-app-id>",
scopes: ["shopping:read", "shopping:write", "store:read", "store:write"],
resources: ["https://shopping.your-app.com/api", "https://store.your-app.com/api"],
)
let client = LogtoClient(useConfig: config)

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.

Somit können im obigen Fall die Berechtigungen aus der Definition in Logto vereinfacht werden, beide API-Ressourcen können read und write Berechtigungen ohne Präfix haben. Dann, in der Logto-Konfiguration:

ContentView.swift
let config = try? LogtoConfig(
endpoint: "<your-logto-endpoint>",
appId: "<your-app-id>",
scopes: ["read", "write"],
resources: ["https://shopping.your-app.com/api", "https://store.your-app.com/api"],
)
let client = LogtoClient(useConfig: config)

Für jede API-Ressource wird sowohl read als auch write Berechtigungen angefordert.

hinweis:

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.

Zugangstoken für die API-Ressource abrufen

Um das Zugangstoken für eine spezifische API-Ressource abzurufen, kannst du die Methode getAccessToken verwenden:

ContentView.swift
let accessToken = try await client.getAccessToken(for: "https://shopping.your-app.com/api")

Diese Methode gibt ein JWT-Zugangstoken zurück, das verwendet werden kann, um auf die API-Ressource zuzugreifen, wenn der Benutzer die entsprechenden Berechtigungen hat. Wenn das aktuell zwischengespeicherte Zugangstoken abgelaufen ist, versucht diese Methode automatisch, ein Auffrischungstoken zu verwenden, um ein neues Zugangstoken zu erhalten.

Zugangstoken an Anfrage-Header anhängen

Platziere das Token im Authorization-Feld der HTTP-Header im Bearer-Format (Bearer YOUR_TOKEN), und du bist startklar.

hinweis:

Der Integrationsablauf des Bearer-Tokens kann je nach verwendetem Framework oder Anfrager variieren. Wähle deinen eigenen Weg, um den Anfrage-Authorization-Header anzuwenden.

await LogtoRequest.get(
useSession: session,
endpoint: userInfoEndpoint,
headers: ["Authorization": "Bearer \(accessToken)"]
)

Weiterführende Lektüre

Endbenutzerflüsse: Authentifizierungsflüsse, Kontoflüsse und Organisationsflüsse Connectors konfigurieren Autorisierung (Authorization)