Personaliza el FlutterFlow CustomAuthManager usando Logto SDK
FlutterFlow tiene una función incorporada de autenticación personalizada que te permite autenticar usuarios usando tu propio backend. Sin embargo, el flujo de autenticación personalizada incorporado fue diseñado para trabajar con una sola llamada a la API de autenticación. Si estás utilizando un Proveedor de Identidad (IdP) de terceros, la solicitud de autenticación solo se puede realizar utilizando el tipo de concesión Resource Owner Password Credentials
, lo cual no se recomienda para uso en producción. Consulta Tipo de concesión ropc obsoleto para más detalles.
Un flujo de autenticación estándar de OpenID Connect (OIDC) involucra múltiples pasos, como autorización, intercambio de tokens y recuperación de información del usuario. Para implementar un flujo de autenticación OIDC estándar con un IdP como Logto, necesitas personalizar la clase CustomAuthManager
en FlutterFlow.
Este tutorial te mostrará cómo personalizar la clase CustomAuthManager
en FlutterFlow usando Logto Flutter SDK. Puedes aprovechar el SDK de Logto para el flujo de autenticación OIDC estándar mientras mantienes los beneficios del constructor de interfaz de usuario de FlutterFlow.
- El paquete Logto SDK está disponible en pub.dev y en el repositorio de GitHub de Logto.
- El SDK actualmente solo es adecuado para plataformas Android e iOS.
Prerrequisitos
- Una cuenta de Logto Cloud o un Logto autoalojado.
- Crear una aplicación Flutter de Logto.
- Un proyecto de FlutterFlow.
Habilitar código personalizado en FlutterFlow
Para personalizar la clase CustomAuthManager
, necesitas habilitar la función de código personalizado en FlutterFlow. Sigue la guía Gestionar código personalizado en GitHub para sincronizar tu proyecto de FlutterFlow con GitHub.
Gestionar código personalizado en GitHub es una función premium en FlutterFlow. Necesitas actualizar tu FlutterFlow al plan pro para habilitar esta función.
Una vez hecho esto, tendrás tres ramas diferentes en tu repositorio de GitHub de FlutterFlow:
main
: La rama principal para el proyecto Flutter. Necesitarás esta rama para desplegar tu proyecto.flutterflow
: La rama dondeFlutterFlow
sincronizará los cambios desde el editor de FlutterFlow.develop
: La rama donde puedes modificar tu código personalizado.
Crea tu interfaz de usuario en FlutterFlow
Primero, crea tu interfaz de usuario en FlutterFlow. Puedes seguir la documentación de FlutterFlow para crear tu interfaz de usuario según tus requisitos. Para este tutorial, como requisito mínimo, crearemos dos páginas:
- Una página de inicio simple con un botón de inicio de sesión.
- Una página de perfil de usuario para mostrar la información del usuario y un botón de cierre de sesión.
Ve a la página App Settings
-> Authentication
y habilita la autenticación personalizada. Esto creará una clase CustomAuthManager
en tu proyecto de FlutterFlow.
Una vez que tengas la interfaz de usuario lista, navega a la página integrations
-> GitHub
y haz clic en el botón Push to Repository
para enviar los cambios a la rama flutterflow
.
Personaliza el CustomAuthManager
Cambia a la rama develop
en tu repositorio de GitHub y fusiona los últimos cambios de la rama flutterflow
. Incluyendo tus páginas de interfaz de usuario y la clase CustomAuthManager
preconstruida.
Instala la dependencia Logto SDK
Agrega la dependencia Logto SDK a tu proyecto.
flutter pub add logto_dart_sdk
Paquete Http opcional:
El cliente Logto requiere un cliente http para realizar llamadas a la API. Puedes usar el paquete http
o cualquier otro paquete de cliente http de tu elección.
flutter pub add http
Actualiza el UserProvider
Agrega la clase OpenIdClaims
a la clase CustomAuthUserProvider
para almacenar la información del usuario.
La clase
OpenIdClaims
es parte del SDK de Logto, que proporcionará los reclamosid_token
para el usuario autenticado.
// 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;
}
/// Genera un flujo del usuario autenticado.
BehaviorSubject<FlutterFlowAuthAuthUser> flutterFlowAuthAuthUserSubject =
BehaviorSubject.seeded(FlutterFlowAuthAuthUser(loggedIn: false));
Stream<FlutterFlowAuthAuthUser> flutterFlowAuthAuthUserStream() =>
flutterFlowAuthAuthUserSubject
.asBroadcastStream()
.map((user) => currentUser = user);
Inicializa el cliente logto en CustomAuthManager
Inicializa el cliente Logto en la clase CustomAuthManager
.
// 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}) {
// Update the current user stream.
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('Error initializing auth: $e');
}
}
_updateCurrentUser(
loggedIn: idToken != null, uid: idToken?.subject, idToken: idToken);
}
}
FlutterFlowAuthAuthUser? currentUser;
bool get loggedIn => currentUser?.loggedIn ?? false;
El método initialize
inicializará el cliente Logto y actualizará el flujo de usuario actual con el estado de autenticación del usuario persistido en el almacenamiento local.
El SDK de Logto utiliza el paquete flutter_secure_storage para almacenar de manera segura la información de autenticación del usuario.
Implementa el método de inicio de sesión
Llama al método LogtoClient.signIn
para iniciar un flujo de autenticación OIDC estándar. La página de inicio de sesión de Logto se abrirá en una vista web usando flutter_web_auth.
// 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,
);
}
LogtoClient manejará los pasos de autorización, intercambio de tokens y recuperación de información del usuario. Una vez que el usuario esté autenticado, los idTokenClaims
se almacenarán en el almacenamiento local. Recupera los idTokenClaims
del LogtoClient y actualiza el flujo de usuario actual.
Implementa el método de cierre de sesión
// lib/auth/custom_auth/custom_auth_manager.dart
Future signOut() async {
await logtoClient.signOut();
flutterFlowAuthAuthUserSubject.add(
FlutterFlowAuthAuthUser(loggedIn: false),
);
}
Actualiza los métodos utilitarios de autenticación
- Agrega el getter
authManager
para acceder a la instancia deCustomAuthManager
. - Agrega el getter
currentUserUid
para obtener el uid del usuario actual. - Agrega el getter
currentUserData
para obtener los datos del usuario actual. - Agrega el getter
logtoClient
para acceder a la instancia del cliente Logto.
// 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;
Integra la autenticación personalizada en tu interfaz de usuario
Página de inicio
Llama al método authManager.signIn
para iniciar el flujo de autenticación cuando el usuario haga clic en el botón de inicio de sesión.
redirectUri
es la URL de callback que se utilizará para capturar el callback de autorización desde la página de inicio de sesión de Logto. Consulta el Flutter SDK para más detalles sobre el 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',
// ...
)
Página de perfil de usuario
Usa los getters utilitarios de autenticación para acceder a los datos del usuario actual y a la instancia del cliente Logto.
// 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}',
),
]
Implementa el método de cierre de sesión cuando el usuario haga clic en el botón de cierre de sesión.
// lib/pages/user/user_widget.dart
FFButtonWidget(
onPressed: () async {
await authManager.signOut();
context.replaceNamed('HomePage');
},
text: 'Sign Out',
// ...
)
Lecturas adicionales
El SDK de Logto proporciona más métodos para interactuar con la API de Logto. Puedes personalizar aún más la clase CustomAuthManager
para implementar más funciones.
Solución de problemas de dependencias
flutter_secure_storage
Usamos flutter_secure_storage para implementar el almacenamiento seguro persistente de tokens multiplataforma. Bajo el capó:
- Se utiliza Keychain para iOS
- Se utiliza cifrado AES para Android.
Configurar la versión de Android:
En [project]/android/app/build.gradle establece minSdkVersion a >= 18.
android {
...
defaultConfig {
...
minSdkVersion 18
...
}
}
Desactivar la copia de seguridad automática:
Por defecto, Android realiza copias de seguridad de los datos en Google Drive. Esto puede causar la excepción java.security.InvalidKeyException:Failed to unwrap key.
Para evitar esto, puedes desactivar la copia de seguridad automática para tu aplicación o excluir sharedprefs de FlutterSecureStorage.
-
Para desactivar la copia de seguridad automática, ve a tu archivo de manifiesto de la aplicación y establece el valor booleano android:allowBackup:
<manifest ... >
...
<application
android:allowBackup="false"
android:fullBackupContent="false"
...
>
...
</application>
</manifest> -
Excluir sharedprefs de FlutterSecureStorage.
Si necesitas habilitar el android:fullBackupContent para tu aplicación. Configura una regla de copia de seguridad para excluir las preferencias utilizadas por el plugin:
<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>Por favor, consulta flutter_secure_storage para más detalles.
flutter_web_auth
flutter_web_auth se utiliza detrás del SDK de flutter de Logto. Confiamos en su interfaz de interacción basada en webview para abrir las páginas de autorización de Logto.
Este plugin utiliza ASWebAuthenticationSession en iOS 12+ y macOS 10.15+, SFAuthenticationSession en iOS 11, Chrome Custom Tabs en Android y abre una nueva ventana en Web. Puedes construirlo con iOS 8+, pero actualmente solo es compatible con iOS 11 o superior.
Registrar la URL de callback en Android
Para capturar la URL de callback desde la página web de inicio de sesión de Logto, necesitarás registrar tu redirectUri de inicio de sesión en el AndroidManifest.xml.
<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>