Pular para o conteúdo principal

Personalizar o FlutterFlow CustomAuthManager usando Logto SDK

FlutterFlow possui um recurso de autenticação personalizada embutido que permite autenticar usuários usando seu próprio backend. No entanto, o fluxo de autenticação personalizada embutido foi projetado para funcionar com uma única chamada de API de autenticação. Se você estiver usando um Provedor de Identidade (IdP) de terceiros, a solicitação de autenticação só pode ser feita usando o tipo de concessão Resource Owner Password Credentials, o que não é recomendado para uso em produção. Veja Tipo de concessão ropc obsoleto para mais detalhes.

Um fluxo de autenticação padrão OpenID Connect (OIDC) envolve várias etapas, como autorização, troca de tokens e recuperação de informações do usuário. Para implementar um fluxo de autenticação OIDC padrão com um IdP como Logto, você precisa personalizar a classe CustomAuthManager no FlutterFlow.

Este tutorial mostrará como personalizar a classe CustomAuthManager no FlutterFlow usando o Logto Flutter SDK. Você pode aproveitar o Logto SDK para o fluxo de autenticação OIDC padrão enquanto mantém os benefícios do construtor de interface do FlutterFlow.

dica:
  • O pacote Logto SDK está disponível no pub.dev e no repositório github do Logto.
  • O SDK atualmente é adequado apenas para plataformas Android e iOS.

Pré-requisitos

Habilitar código personalizado no FlutterFlow

Para personalizar a classe CustomAuthManager, você precisa habilitar o recurso de código personalizado no FlutterFlow. Siga o guia Gerenciar Código Personalizado no GitHub para sincronizar seu projeto FlutterFlow com o GitHub.

nota:

Gerenciar código personalizado no GitHub é um recurso premium no FlutterFlow. Você precisa atualizar seu FlutterFlow para o plano pro para habilitar esse recurso.

Uma vez feito isso, você terá três branches diferentes no seu repositório GitHub FlutterFlow:

  1. main: A branch principal para o projeto flutter. Você precisará dessa branch para implantar seu projeto.
  2. flutterflow: A branch onde o FlutterFlow sincronizará as alterações do editor FlutterFlow.
  3. develop: A branch onde você pode modificar seu código personalizado.

Crie sua interface no FlutterFlow

Primeiro, crie sua interface no FlutterFlow. Você pode seguir a documentação do FlutterFlow para criar sua interface com base em seus requisitos. Para este tutorial, como requisito mínimo, criaremos duas páginas:

  1. Uma página inicial simples com um botão de login.
  2. Uma página de perfil do usuário para exibir informações do usuário e botão de logout.

Vá para App Settings -> página Authentication e habilite a autenticação personalizada. Isso criará uma classe CustomAuthManager no seu projeto FlutterFlow.

Autenticação personalizada do FlutterFlow

Uma vez que você tenha a interface pronta, navegue até integrations -> página GitHub e clique no botão Push to Repository para enviar as alterações para a branch flutterflow.

Envio para o GitHub do FlutterFlow

Personalizar o CustomAuthManager

Mude para a branch develop no seu repositório GitHub e mescle as últimas alterações da branch flutterflow. Incluindo suas páginas de interface e a classe CustomAuthManager pré-construída.

Instalar a dependência do Logto SDK

Adicione a dependência do Logto SDK ao seu projeto.

  flutter pub add logto_dart_sdk
nota:

Pacote Http opcional:

O cliente Logto requer um cliente http para fazer chamadas de API. Você pode usar o pacote http ou qualquer outro pacote de cliente http de sua escolha.

  flutter pub add http

Atualizar o UserProvider

Adicione a classe OpenIdClaims à classe CustomAuthUserProvider para armazenar as informações do usuário.

A classe OpenIdClaims faz parte do Logto SDK, que fornecerá as reivindicações do id_token para o usuário 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;
}

/// Gera um fluxo do usuário autenticado.
BehaviorSubject<FlutterFlowAuthAuthUser> flutterFlowAuthAuthUserSubject =
BehaviorSubject.seeded(FlutterFlowAuthAuthUser(loggedIn: false));
Stream<FlutterFlowAuthAuthUser> flutterFlowAuthAuthUserStream() =>
flutterFlowAuthAuthUserSubject
.asBroadcastStream()
.map((user) => currentUser = user);

Inicializar o cliente logto no CustomAuthManager

Inicialize o cliente Logto na classe 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}) {
// Atualiza o fluxo do usuário atual.
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('Erro ao inicializar a autenticação: $e');
}
}

_updateCurrentUser(
loggedIn: idToken != null, uid: idToken?.subject, idToken: idToken);
}
}

FlutterFlowAuthAuthUser? currentUser;
bool get loggedIn => currentUser?.loggedIn ?? false;

O método initialize inicializará o cliente Logto e atualizará o fluxo de usuário atual com o status de autenticação do usuário persistido no armazenamento local.

O Logto SDK usa o pacote flutter_secure_storage para armazenar as informações de autenticação do usuário de forma segura.

Implementar o método de login

Chame o método LogtoClient.signIn para iniciar um fluxo de autenticação OIDC padrão. A página de login do Logto será aberta em uma webview 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,
);
}

O LogtoClient lidará com as etapas de autorização, troca de tokens e recuperação de informações do usuário. Uma vez que o usuário é autenticado, as idTokenClaims serão armazenadas no armazenamento local. Recupere as idTokenClaims do LogtoClient e atualize o fluxo de usuário atual.

Implementar o método de logout

// lib/auth/custom_auth/custom_auth_manager.dart

Future signOut() async {
await logtoClient.signOut();

flutterFlowAuthAuthUserSubject.add(
FlutterFlowAuthAuthUser(loggedIn: false),
);
}

Atualizar os métodos utilitários de autenticação

  • Adicione o getter authManager para acessar a instância do CustomAuthManager.
  • Adicione o getter currentUserUid para obter o uid do usuário atual.
  • Adicione o getter currentUserData para obter os dados do usuário atual.
  • Adicione o getter logtoClient para acessar a instância do 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;

Integrar a autenticação personalizada na sua interface

Página Inicial

Chame o método authManager.signIn para iniciar o fluxo de autenticação quando o usuário clicar no botão de login.

redirectUri é a URL de callback que será usada para capturar o callback de autorização da página de login do Logto. Veja o Flutter SDK para mais detalhes sobre o 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 do Usuário

Use os getters utilitários de autenticação para acessar os dados do usuário atual e a instância do 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}',
),
]

Implemente o método de logout quando o usuário clicar no botão de logout.

// lib/pages/user/user_widget.dart

FFButtonWidget(
onPressed: () async {
await authManager.signOut();

context.replaceNamed('HomePage');
},
text: 'Sign Out',
// ...
)

Leituras adicionais

O Logto SDK fornece mais métodos para interagir com a API do Logto. Você pode personalizar ainda mais a classe CustomAuthManager para implementar mais recursos.

Solução de problemas de dependência

flutter_secure_storage

Usamos flutter_secure_storage para implementar o armazenamento seguro persistente de tokens em várias plataformas. Sob o capô:

  • Keychain é usado para iOS
  • Criptografia AES é usada para Android.

Configurar versão do Android:

Em [project]/android/app/build.gradle defina minSdkVersion para >= 18.

  android {
...

defaultConfig {
...
minSdkVersion 18
...
}
}

Desativar backup automático:

nota:

Por padrão, o Android faz backup dos dados no Google Drive. Isso pode causar a exceção java.security.InvalidKeyException:Failed to unwrap key.

Para evitar isso, você pode desativar o backup automático para seu aplicativo ou excluir sharedprefs do FlutterSecureStorage.

  1. Para desativar o backup automático, vá para o arquivo de manifesto do seu aplicativo e defina o valor booleano android:allowBackup:

    <manifest ... >
    ...
    <application
    android:allowBackup="false"
    android:fullBackupContent="false"
    ...
    >
    ...
    </application>
    </manifest>

  2. Excluir sharedprefs do FlutterSecureStorage.

    Se você precisar habilitar o android:fullBackupContent para seu aplicativo. Configure uma regra de backup para excluir as prefs usadas pelo 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, verifique flutter_secure_storage para mais detalhes.

flutter_web_auth

flutter_web_auth é usado por trás do SDK flutter do Logto. Nós confiamos em sua interface de interação baseada em webview para abrir as páginas de autorização do Logto.

nota:

Este plugin usa ASWebAuthenticationSession no iOS 12+ e macOS 10.15+, SFAuthenticationSession no iOS 11, Chrome Custom Tabs no Android e abre uma nova janela na Web. Você pode construí-lo com iOS 8+, mas atualmente é suportado apenas por iOS 11 ou superior.

Registrar a URL de callback no Android

Para capturar a URL de callback da página de login do Logto, você precisará registrar seu redirectUri de login no 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>