본문으로 건너뛰기

Logto SDK를 사용하여 FlutterFlow CustomAuthManager 사용자 정의

FlutterFlow에는 사용자 고유의 백엔드를 사용하여 사용자를 인증할 수 있는 사용자 정의 인증 기능이 내장되어 있습니다. 그러나 내장된 사용자 정의 인증 흐름은 단일 인증 API 호출과 함께 작동하도록 설계되었습니다. 타사 아이덴티티 제공자 (IdP)를 사용하는 경우, 인증 요청은 Resource Owner Password Credentials 승인 유형을 사용하여만 수행할 수 있으며, 이는 프로덕션 사용에 권장되지 않습니다. 자세한 내용은 Deprecated ropc grant type을 참조하세요.

표준 OpenID Connect (OIDC) 인증 흐름은 인가 (Authorization), 토큰 교환, 사용자 정보 검색과 같은 여러 단계를 포함합니다. Logto와 같은 IdP로 표준 OIDC 인증 흐름을 구현하려면 FlutterFlow의 CustomAuthManager 클래스를 사용자 정의해야 합니다.

이 튜토리얼에서는 Logto Flutter SDK를 사용하여 FlutterFlow의 CustomAuthManager 클래스를 사용자 정의하는 방법을 보여줍니다. FlutterFlow UI 빌더의 이점을 유지하면서 표준 OIDC 인증 흐름을 위해 Logto SDK를 활용할 수 있습니다.

:
  • Logto SDK 패키지는 pub.dev와 Logto GitHub 저장소에서 사용할 수 있습니다.
  • SDK는 현재 Android 및 iOS 플랫폼에만 적합합니다.

사전 준비 사항

FlutterFlow 사용자 정의 코드 활성화

CustomAuthManager 클래스를 사용자 정의하려면 FlutterFlow에서 사용자 정의 코드 기능을 활성화해야 합니다. FlutterFlow 프로젝트를 GitHub와 동기화하려면 Manage Custom Code In GitHub 가이드를 따르세요.

노트:

GitHub에서 사용자 정의 코드를 관리하는 것은 FlutterFlow의 프리미엄 기능입니다. 이 기능을 활성화하려면 FlutterFlow를 프로 플랜으로 업그레이드해야 합니다.

완료되면 GitHub FlutterFlow 저장소에 세 가지 다른 브랜치가 생성됩니다:

  1. main: Flutter 프로젝트의 메인 브랜치입니다. 이 브랜치를 사용하여 프로젝트를 배포해야 합니다.
  2. flutterflow: FlutterFlow 편집기에서 변경 사항을 동기화할 브랜치입니다.
  3. develop: 사용자 정의 코드를 수정할 수 있는 브랜치입니다.

FlutterFlow에서 UI 생성

먼저, FlutterFlow에서 UI를 생성하세요. 요구 사항에 따라 UI를 생성하려면 FlutterFlow 문서를 참조할 수 있습니다. 이 튜토리얼에서는 최소 요구 사항으로 두 페이지를 생성합니다:

  1. 로그인 버튼이 있는 간단한 홈 페이지.
  2. 사용자 정보와 로그아웃 버튼을 표시할 사용자 프로필 페이지.

App Settings -> Authentication 페이지로 이동하여 사용자 정의 인증을 활성화하세요. 이렇게 하면 FlutterFlow 프로젝트에 CustomAuthManager 클래스가 생성됩니다.

FlutterFlow 사용자 정의 인증

UI가 준비되면 integrations -> GitHub 페이지로 이동하여 Push to Repository 버튼을 클릭하여 변경 사항을 flutterflow 브랜치에 푸시하세요.

FlutterFlow GitHub 푸시

CustomAuthManager 사용자 정의

GitHub 저장소에서 develop 브랜치로 전환하고 flutterflow 브랜치의 최신 변경 사항을 병합하세요. UI 페이지와 사전 빌드된 CustomAuthManager 클래스가 포함됩니다.

Logto SDK 종속성 설치

프로젝트에 Logto SDK 종속성을 추가하세요.

  flutter pub add logto_dart_sdk
노트:

선택적 Http 패키지:

Logto 클라이언트는 API 호출을 수행하기 위해 http 클라이언트가 필요합니다. http 패키지 또는 원하는 다른 http 클라이언트 패키지를 사용할 수 있습니다.

  flutter pub add http

UserProvider 업데이트

사용자 정보를 저장하기 위해 CustomAuthUserProvider 클래스에 OpenIdClaims 클래스를 추가하세요.

OpenIdClaims 클래스는 인증된 사용자의 id_token 클레임을 제공하는 Logto SDK의 일부입니다.

// 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;
}

/// 인증된 사용자의 스트림을 생성합니다.
BehaviorSubject<FlutterFlowAuthAuthUser> flutterFlowAuthAuthUserSubject =
BehaviorSubject.seeded(FlutterFlowAuthAuthUser(loggedIn: false));
Stream<FlutterFlowAuthAuthUser> flutterFlowAuthAuthUserStream() =>
flutterFlowAuthAuthUserSubject
.asBroadcastStream()
.map((user) => currentUser = user);

CustomAuthManager에서 logto 클라이언트 초기화

CustomAuthManager 클래스에서 Logto 클라이언트를 초기화하세요.

// 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}) {
// 현재 사용자 스트림을 업데이트합니다.
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('인증 초기화 오류: $e');
}
}

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

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

initialize 메서드는 Logto 클라이언트를 초기화하고 로컬 저장소에 저장된 사용자 인증 상태로 현재 사용자 스트림을 업데이트합니다.

Logto SDK는 flutter_secure_storage 패키지를 사용하여 사용자 인증 정보를 안전하게 저장합니다.

로그인 메서드 구현

LogtoClient.signIn 메서드를 호출하면 표준 OIDC 인증 흐름이 시작됩니다. Logto 로그인 페이지는 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는 인가, 토큰 교환, 사용자 정보 검색 단계를 처리합니다. 사용자가 인증되면 idTokenClaims가 로컬 저장소에 저장됩니다. LogtoClient에서 idTokenClaims를 검색하고 현재 사용자 스트림을 업데이트합니다.

로그아웃 메서드 구현

// lib/auth/custom_auth/custom_auth_manager.dart

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

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

인증 유틸리티 메서드 업데이트

  • CustomAuthManager 인스턴스에 접근하기 위한 authManager getter를 추가하세요.
  • 현재 사용자 uid를 가져오기 위한 currentUserUid getter를 추가하세요.
  • 현재 사용자 데이터를 가져오기 위한 currentUserData getter를 추가하세요.
  • Logto 클라이언트 인스턴스에 접근하기 위한 logtoClient getter를 추가하세요.
// 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;

UI에 사용자 정의 인증 통합

홈 페이지

사용자가 로그인 버튼을 클릭할 때 인증 흐름을 시작하기 위해 authManager.signIn 메서드를 호출하세요.

redirectUri는 Logto 로그인 페이지에서 인가 콜백을 캡처하는 데 사용되는 콜백 URL입니다. redirectUri에 대한 자세한 내용은 Flutter SDK를 참조하세요.

// 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',
// ...
)

사용자 프로필 페이지

현재 사용자 데이터와 Logto 클라이언트 인스턴스에 접근하기 위해 인증 유틸리티 getter를 사용하세요.

// 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}',
),
]

사용자가 로그아웃 버튼을 클릭할 때 로그아웃 메서드를 구현하세요.

// lib/pages/user/user_widget.dart

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

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

추가 읽을거리

Logto SDK는 Logto API와 상호작용하기 위한 더 많은 메서드를 제공합니다. 더 많은 기능을 구현하기 위해 CustomAuthManager 클래스를 추가로 사용자 정의할 수 있습니다.

종속성 문제 해결

flutter_secure_storage

우리는 flutter_secure_storage를 사용하여 크로스 플랫폼 지속 가능한 보안 토큰 저장소를 구현합니다. 내부적으로:

  • iOS에서는 Keychain이 사용됩니다.
  • Android에서는 AES 암호화가 사용됩니다.

Android 버전 구성:

[project]/android/app/build.gradle에서 minSdkVersion을 >= 18로 설정하세요.

  android {
...

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

자동 백업 비활성화:

노트:

기본적으로 Android는 Google Drive에 데이터를 백업합니다. 이는 예외 java.security.InvalidKeyException:Failed to unwrap key를 발생시킬 수 있습니다.

이를 피하기 위해, 앱에 대한 자동 백업을 비활성화하거나 FlutterSecureStorage에서 sharedprefs를 제외할 수 있습니다.

  1. 자동 백업을 비활성화하려면, 앱 매니페스트 파일로 가서 boolean 값 android:allowBackup을 설정하세요:

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

  2. FlutterSecureStorage에서 sharedprefs를 제외하세요.

    앱에 대해 android:fullBackupContent를 활성화해야 하는 경우, 플러그인이 사용하는 prefs를 제외하는 백업 규칙을 설정하세요:

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

    자세한 내용은 flutter_secure_storage를 확인하세요.

flutter_web_auth

flutter_web_auth 는 Logto의 flutter SDK 뒤에서 사용됩니다. 우리는 Logto의 인가 (Authorization) 페이지를 열기 위해 웹뷰 기반 상호작용 인터페이스에 의존합니다.

노트:

이 플러그인은 iOS 12+ 및 macOS 10.15+에서는 ASWebAuthenticationSession을 사용하고, iOS 11에서는 SFAuthenticationSession을 사용하며, Android에서는 Chrome Custom Tabs를 사용하고, 웹에서는 새 창을 엽니다. iOS 8+로 빌드할 수 있지만, 현재는 iOS 11 이상에서만 지원됩니다.

Android에서 콜백 URL 등록하기

Logto의 로그인 웹 페이지에서 콜백 URL을 캡처하려면, AndroidManifest.xml에 로그인 redirectUri를 등록해야 합니다.

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