Zum Hauptinhalt springen

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.

tipp
  • 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

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.

hinweis

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:

  1. main: Der Hauptbranch für das Flutter-Projekt. Du benötigst diesen Branch, um dein Projekt bereitzustellen.
  2. flutterflow: Der Branch, in dem FlutterFlow die Änderungen aus dem FlutterFlow-Editor synchronisiert.
  3. 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:

  1. Eine einfache Startseite mit einem Login-Button.
  2. 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.

FlutterFlow benutzerdefinierte Authentifizierung

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.

FlutterFlow GitHub Push

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
hinweis

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 die id_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 die CustomAuthManager-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:

hinweis

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.

  1. 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>

  2. 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.

hinweis

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>