Anpassen des FlutterFlow CustomAuthManager mit Logto SDK
FlutterFlow verfügt über eine integrierte benutzerdefinierte Authentifizierung, die es ermöglicht, Benutzer über dein eigenes Backend zu authentifizieren. Der integrierte benutzerdefinierte Authentifizierungsablauf wurde jedoch so konzipiert, dass er mit einem einzigen Authentifizierungs-API-Aufruf funktioniert. Wenn du einen Drittanbieter-Identitätsanbieter (IdP) verwendest, kann die Authentifizierungsanfrage nur mit dem Resource Owner Password Credentials
Grant-Typ durchgeführt werden, was für die Produktion nicht empfohlen wird. Siehe Veralteter ropc Grant-Typ für weitere Details.
Ein standardmäßiger OpenID Connect (OIDC) Authentifizierungsablauf umfasst mehrere Schritte, wie Autorisierung, Token-Austausch und Abruf von Benutzerinformationen. Um einen standardmäßigen OIDC-Authentifizierungsablauf mit einem IdP wie Logto zu implementieren, musst du die CustomAuthManager
-Klasse in FlutterFlow anpassen.
Dieses Tutorial zeigt dir, wie du die CustomAuthManager
-Klasse in FlutterFlow mit dem Logto Flutter SDK anpasst. Du kannst die Vorteile des Logto SDK für den standardmäßigen OIDC-Authentifizierungsablauf nutzen und gleichzeitig die Vorteile des FlutterFlow UI-Builders beibehalten.
- Das Logto SDK-Paket ist auf pub.dev und im Logto GitHub-Repository verfügbar.
- Das SDK ist derzeit nur für Android- und iOS-Plattformen geeignet.
Voraussetzungen
- Ein Logto Cloud Konto oder ein selbst gehostetes Logto.
- Erstelle eine Logto Flutter-Anwendung.
- Ein FlutterFlow-Projekt.
Aktivieren des benutzerdefinierten Codes in FlutterFlow
Um die CustomAuthManager
-Klasse anzupassen, musst du die benutzerdefinierte Code-Funktion in FlutterFlow aktivieren. Folge dem Leitfaden Manage Custom Code In GitHub, um dein FlutterFlow-Projekt mit GitHub zu synchronisieren.
Das Verwalten von benutzerdefiniertem Code in GitHub ist eine Premium-Funktion in FlutterFlow. Du musst dein FlutterFlow auf den Pro-Plan upgraden, um diese Funktion zu aktivieren.
Sobald dies erledigt ist, hast du drei verschiedene Branches in deinem GitHub FlutterFlow-Repository:
main
: Der Hauptbranch für das Flutter-Projekt. Du benötigst diesen Branch, um dein Projekt bereitzustellen.flutterflow
: Der Branch, in demFlutterFlow
die Änderungen aus dem FlutterFlow-Editor synchronisiert.develop
: Der Branch, in dem du deinen benutzerdefinierten Code ändern kannst.
Erstelle dein UI in FlutterFlow
Erstelle zuerst dein UI in FlutterFlow. Du kannst der FlutterFlow-Dokumentation folgen, um dein UI basierend auf deinen Anforderungen zu erstellen. Für dieses Tutorial erstellen wir als Mindestanforderung zwei Seiten:
- Eine einfache Startseite mit einem Login-Button.
- Eine Benutzerprofilseite, um Benutzerinformationen und einen Logout-Button anzuzeigen.
Gehe zur Seite App Settings
-> Authentication
und aktiviere die benutzerdefinierte Authentifizierung. Dadurch wird eine CustomAuthManager
-Klasse in deinem FlutterFlow-Projekt erstellt.
Sobald du das UI fertig hast, navigiere zur Seite integrations
-> GitHub
und klicke auf den Button Push to Repository
, um die Änderungen in den flutterflow
Branch zu übertragen.
Passe den CustomAuthManager an
Wechsle zum develop
Branch in deinem GitHub-Repository und führe die neuesten Änderungen aus dem flutterflow
Branch zusammen. Einschließlich deiner UI-Seiten und der vorgefertigten CustomAuthManager
-Klasse.
Installiere die Logto SDK-Abhängigkeit
Füge die Logto SDK-Abhängigkeit zu deinem Projekt hinzu.
flutter pub add logto_dart_sdk
Optionales Http-Paket:
Der Logto-Client benötigt einen Http-Client, um API-Aufrufe zu tätigen. Du kannst das http
-Paket oder ein anderes Http-Client-Paket deiner Wahl verwenden.
flutter pub add http
Aktualisiere den UserProvider
Füge die OpenIdClaims
-Klasse zur CustomAuthUserProvider
-Klasse hinzu, um die Benutzerinformationen zu speichern.
Die
OpenIdClaims
-Klasse ist Teil des Logto SDK, das dieid_token
Ansprüche für den authentifizierten Benutzer bereitstellt.
// lib/auth/custom_auth/custom_auth_user_provider.dart
import 'package:logto_dart_sdk/src/modules/id_token.dart';
import 'package:rxdart/rxdart.dart';
import 'custom_auth_manager.dart';
class FlutterFlowAuthAuthUser {
FlutterFlowAuthAuthUser({required this.loggedIn, this.uid, this.idToken});
bool loggedIn;
String? uid;
OpenIdClaims? idToken;
}
/// Generiert einen Stream des authentifizierten Benutzers.
BehaviorSubject<FlutterFlowAuthAuthUser> flutterFlowAuthAuthUserSubject =
BehaviorSubject.seeded(FlutterFlowAuthAuthUser(loggedIn: false));
Stream<FlutterFlowAuthAuthUser> flutterFlowAuthAuthUserStream() =>
flutterFlowAuthAuthUserSubject
.asBroadcastStream()
.map((user) => currentUser = user);
Initialisiere den Logto-Client im CustomAuthManager
Initialisiere den Logto-Client in der CustomAuthManager
-Klasse.
// lib/auth/custom_auth/custom_auth_manager.dart
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
import 'package:logto_dart_sdk/logto_client.dart';
import 'package:logto_dart_sdk/src/modules/id_token.dart';
import 'custom_auth_user_provider.dart';
export 'custom_auth_manager.dart';
class CustomAuthManager {
late LogtoClient logtoClient;
final logtoConfig = const LogtoConfig(
appId: '<YOUR-APP-ID>',
endpoint: '<YOUR-LOGTO-ENDPOINT>');
// ...
FlutterFlowAuthAuthUser? _updateCurrentUser(
{bool loggedIn = false, String? uid, OpenIdClaims? idToken}) {
// Aktualisiere den aktuellen Benutzerstream.
final updatedUser = FlutterFlowAuthAuthUser(
loggedIn: loggedIn,
uid: uid,
idToken: idToken,
);
flutterFlowAuthAuthUserSubject.add(updatedUser);
return updatedUser;
}
Future initialize() async {
logtoClient = LogtoClient(config: logtoConfig, httpClient: http.Client());
late OpenIdClaims? idToken;
try {
idToken = await logtoClient.idTokenClaims;
} catch (e) {
if (kDebugMode) {
print('Fehler bei der Initialisierung der Authentifizierung: $e');
}
}
_updateCurrentUser(
loggedIn: idToken != null, uid: idToken?.subject, idToken: idToken);
}
}
FlutterFlowAuthAuthUser? currentUser;
bool get loggedIn => currentUser?.loggedIn ?? false;
Die initialize
-Methode initialisiert den Logto-Client und aktualisiert den aktuellen Benutzerstream mit dem in der lokalen Speicherung gespeicherten Authentifizierungsstatus des Benutzers.
Das Logto SDK verwendet das flutter_secure_storage Paket, um die Benutzer-Authentifizierungsinformationen sicher zu speichern.
Implementiere die Anmeldemethode
Der Aufruf der LogtoClient.signIn
-Methode wird einen standardmäßigen OIDC-Authentifizierungsablauf einleiten. Die Logto-Anmeldeseite wird in einer Webansicht mit flutter_web_auth geöffnet.
// lib/auth/custom_auth/custom_auth_manager.dart
Future<FlutterFlowAuthAuthUser?> signIn(
String redirectUri,
) async {
await logtoClient.signIn(redirectUri);
var idTokenClaims = await logtoClient.idTokenClaims;
return _updateCurrentUser(
loggedIn: idTokenClaims != null,
uid: idTokenClaims?.subject,
idToken: idTokenClaims,
);
}
Der LogtoClient wird die Schritte der Autorisierung, des Token-Austauschs und des Abrufs von Benutzerinformationen handhaben. Sobald der Benutzer authentifiziert ist, werden die idTokenClaims
in der lokalen Speicherung gespeichert.
Rufe die idTokenClaims
vom LogtoClient ab und aktualisiere den aktuellen Benutzerstream.
Implementiere die Abmeldemethode
// lib/auth/custom_auth/custom_auth_manager.dart
Future signOut() async {
await logtoClient.signOut();
flutterFlowAuthAuthUserSubject.add(
FlutterFlowAuthAuthUser(loggedIn: false),
);
}
Aktualisiere die Auth-Util-Methoden
- Füge den
authManager
Getter hinzu, um auf dieCustomAuthManager
-Instanz zuzugreifen. - Füge den
currentUserUid
Getter hinzu, um die aktuelle Benutzer-UID zu erhalten. - Füge den
currentUserData
Getter hinzu, um die aktuellen Benutzerdaten zu erhalten. - Füge den
logtoClient
Getter hinzu, um auf die Logto-Client-Instanz zuzugreifen.
// lib/auth/custom_auth/auth_util.dart
import 'package:logto_dart_sdk/logto_client.dart';
import 'package:logto_dart_sdk/src/modules/id_token.dart';
import 'custom_auth_manager.dart';
export 'custom_auth_manager.dart';
final _authManager = CustomAuthManager();
CustomAuthManager get authManager => _authManager;
String get currentUserUid => currentUser?.uid ?? '';
OpenIdClaims? get currentUserData => currentUser?.idToken;
LogtoClient get logtoClient => _authManager.logtoClient;
Integriere die benutzerdefinierte Authentifizierung in dein UI
Startseite
Rufe die authManager.signIn
-Methode auf, um den Authentifizierungsablauf zu starten, wenn der Benutzer auf den Anmeldebutton klickt.
redirectUri
ist die Callback-URL, die verwendet wird, um den Autorisierungs-Callback von der Logto-Anmeldeseite zu erfassen. Siehe das Flutter SDK für weitere Details zur redirectUri.
// lib/pages/home_page/home_page_widget.dart
final redirectUri = 'io.logto://callback';
// ...
FFButtonWidget(
onPressed: () async {
GoRouter.of(context).prepareAuthEvent();
await authManager.signIn(redirectUri);
context.replaceNamed('user');
},
text: 'Sign In',
// ...
)
Benutzerprofilseite
Verwende die Auth-Util-Getter, um auf die aktuellen Benutzerdaten und die Logto-Client-Instanz zuzugreifen.
// lib/pages/user/user_widget.dart
import '/auth/custom_auth/auth_util.dart';
// ...
children: [
Text(
'User ID: $currentUserUid',
),
Text(
'Display Name: ${currentUserData?.name}',
),
Text(
'Username: ${currentUserData?.username}',
),
Text(
'Email: ${currentUserData?.emailVerified ?? currentUserData?.email}',
),
]
Implementiere die Abmeldemethode, wenn der Benutzer auf den Abmeldebutton klickt.
// lib/pages/user/user_widget.dart
FFButtonWidget(
onPressed: () async {
await authManager.signOut();
context.replaceNamed('HomePage');
},
text: 'Sign Out',
// ...
)
Weiterführende Lektüre
Das Logto SDK bietet weitere Methoden zur Interaktion mit der Logto API. Du kannst die CustomAuthManager
-Klasse weiter anpassen, um weitere Funktionen zu implementieren.
Abhängigkeitsprobleme beheben
flutter_secure_storage
Wir verwenden flutter_secure_storage, um die plattformübergreifende, persistente sichere Token-Speicherung zu implementieren. Unter der Haube:
- Keychain wird für iOS verwendet
- AES-Verschlüsselung wird für Android verwendet.
Android-Version konfigurieren:
In [project]/android/app/build.gradle setze minSdkVersion auf >= 18.
android {
...
defaultConfig {
...
minSdkVersion 18
...
}
}
Autobackup deaktivieren:
Standardmäßig sichert Android Daten auf Google Drive. Dies kann die Ausnahme java.security.InvalidKeyException:Failed to unwrap key verursachen.
Um dies zu vermeiden, kannst du das automatische Backup für deine App deaktivieren oder sharedprefs von FlutterSecureStorage ausschließen.
-
Um das automatische Backup zu deaktivieren, gehe zu deiner App-Manifestdatei und setze den booleschen Wert android:allowBackup:
<manifest ... >
...
<application
android:allowBackup="false"
android:fullBackupContent="false"
...
>
...
</application>
</manifest> -
Schließe sharedprefs von FlutterSecureStorage aus.
Wenn du android:fullBackupContent für deine App aktivieren musst. Richte eine Backup-Regel ein, um die vom Plugin verwendeten Prefs auszuschließen:
<application ...
android:fullBackupContent="@xml/backup_rules">
</application><?xml version="1.0" encoding="utf-8"?>
<full-backup-content>
<exclude domain="sharedpref" path="FlutterSecureStorage"/>
</full-backup-content>Bitte sieh dir flutter_secure_storage für weitere Details an.
flutter_web_auth
flutter_web_auth wird hinter dem flutter SDK von Logto verwendet. Wir verlassen uns auf seine webview-basierte Interaktionsschnittstelle, um die Autorisierungsseiten von Logto zu öffnen.
Dieses Plugin verwendet ASWebAuthenticationSession auf iOS 12+ und macOS 10.15+, SFAuthenticationSession auf iOS 11, Chrome Custom Tabs auf Android und öffnet ein neues Fenster im Web. Du kannst es mit iOS 8+ bauen, aber es wird derzeit nur von iOS 11 oder höher unterstützt.
Registriere die Callback-URL auf Android
Um die Callback-URL von Logtos Anmelde-Webseite zu erfassen, musst du deine Anmelde-redirectUri in der AndroidManifest.xml registrieren.
<activity android:name="com.linusu.flutter_web_auth.CallbackActivity" android:exported="true">
<intent-filter android:label="flutter_web_auth">
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="io.logto"/>
</intent-filter>
</activity>