FirebaseUI를 사용하여 Flutter 앱에 사용자 인증 흐름 추가

1. 시작하기 전에

이 Codelab에서는 FlutterFire UI 패키지를 사용하여 Flutter 앱에 Firebase 인증을 추가하는 방법을 알아봅니다. 이 패키지를 사용하면 Flutter 앱에 이메일/비밀번호 인증과 Google 로그인 인증을 모두 추가할 수 있습니다. 또한 Firebase 프로젝트를 설정하는 방법과 FlutterFire CLI를 사용하여 Flutter 앱에서 Firebase를 초기화하는 방법도 알아봅니다.

전제조건

이 Codelab에서는 개발자가 Flutter 경험이 있다고 가정합니다. 그렇지 않다면 먼저 기본 사항을 배우는 것이 좋습니다. 다음 링크가 도움이 됩니다:

Firebase 경험도 있어야 하지만 Flutter 프로젝트에 Firebase를 추가한 적이 없어도 괜찮습니다. Firebase 콘솔에 익숙하지 않거나 Firebase를 처음 접하는 경우 먼저 다음 링크를 참조하세요.

당신이 만들 것

이 Codelab에서는 인증에 Firebase를 사용하여 Flutter 앱의 인증 흐름을 구축하는 과정을 안내합니다. 애플리케이션에는 로그인 화면, '등록' 화면, 비밀번호 복구 화면, 사용자 프로필 화면이 있습니다.

6604fc9157f2c6ae.pngeab9509a41074930.pngda49189a5838e0bb.pngb2ccfb3632b77878.png

무엇을 배울 것인가

이 Codelab에서는 다음을 다룹니다.

  • Flutter 앱에 Firebase 추가
  • Firebase 콘솔 설정
  • Firebase CLI를 사용하여 애플리케이션에 Firebase 추가
  • FlutterFire CLI를 사용하여 Dart에서 Firebase 구성 생성
  • Flutter 앱에 Firebase 인증 추가
  • 콘솔에서 Firebase 인증 설정
  • firebase_ui_auth 패키지를 사용하여 이메일 및 비밀번호 로그인 추가
  • firebase_ui_auth 패키지로 사용자 등록 추가
  • '비밀번호를 잊으셨나요?' 추가 페이지
  • firebase_ui_auth 로 Google 로그인 추가
  • 여러 로그인 제공업체와 작동하도록 앱을 구성합니다.
  • firebase_ui_auth 패키지를 사용하여 애플리케이션에 사용자 프로필 화면 추가

이 Codelab은 특히 firebase_ui_auth 패키지를 사용하여 강력한 인증 시스템을 추가하는 것과 관련이 있습니다. 보시다시피 위의 모든 기능을 갖춘 이 전체 앱은 약 100줄의 코드로 구현할 수 있습니다.

필요한 것

  • Flutter 및 설치된 SDK에 대한 실무 지식
  • 텍스트 편집기(JetBrains IDE, Android Studio 및 VS Code는 Flutter에서 지원됨)
  • Google Chrome 브라우저 또는 기타 선호하는 Flutter용 개발 대상입니다. (이 Codelab의 일부 터미널 명령어는 Chrome에서 앱을 실행한다고 가정합니다.)

2. Firebase 프로젝트 생성 및 설정

완료해야 할 첫 번째 작업은 Firebase 웹 콘솔에서 Firebase 프로젝트를 만드는 것입니다.

Firebase 프로젝트 만들기

  1. Firebase 에 로그인합니다.
  2. Firebase 콘솔에서 프로젝트 추가 (또는 프로젝트 만들기 )를 클릭하고 Firebase 프로젝트 이름(예: " FlutterFire-UI-Codelab ")을 입력합니다.

df42a5e3d9584b48.png

  1. 프로젝트 생성 옵션을 클릭하세요. 메시지가 표시되면 Firebase 약관에 동의하세요. 이 앱에서는 Analytics를 사용하지 않으므로 Google Analytics 설정을 건너뛰세요.

d1fcec48bf251eaa.png

Firebase 프로젝트에 대해 자세히 알아보려면 Firebase 프로젝트 이해를 참조하세요.

빌드 중인 앱은 Firebase 인증을 사용하여 사용자가 앱에 로그인할 수 있도록 합니다. 또한 새로운 사용자가 Flutter 애플리케이션에서 등록할 수 있습니다.

Firebase 인증은 Firebase 콘솔을 사용하여 활성화해야 하며, 활성화한 후에는 특별한 구성이 필요합니다.

Firebase 인증을 위한 이메일 로그인 활성화

사용자가 웹 앱에 로그인할 수 있도록 하려면 먼저 이메일/비밀번호 로그인 방법을 사용합니다. 나중에 Google 로그인 방법을 추가하게 됩니다.

  1. Firebase 콘솔의 왼쪽 패널에서 빌드 메뉴를 확장합니다.
  2. 인증 을 클릭한 다음 시작하기 버튼, 로그인 방법 탭을 차례로 클릭합니다(또는 로그인 방법 탭으로 직접 이동하려면 여기를 클릭하세요 ).
  3. 로그인 공급자 목록에서 이메일/비밀번호를 클릭하고 활성화 스위치를 켜짐 위치로 설정한 다음 저장 을 클릭합니다. 58e3e3e23c2f16a4.png

3. Flutter 앱 설정

시작하기 전에 시작 코드를 다운로드하고 Firebase CLI를 설치해야 합니다.

시작 코드 받기

명령줄에서 GitHub 저장소를 복제합니다.

git clone https://github.com/flutter/codelabs.git flutter-codelabs

또는 GitHub의 CLI 도구가 설치되어 있는 경우:

gh repo clone flutter/codelabs flutter-codelabs

샘플 코드는 Codelab 컬렉션의 코드가 포함된 flutter-codelabs 디렉터리에 복제되어야 합니다. 이 Codelab의 코드는 하위 디렉터리 flutter-codelabs/firebase-auth-flutterfire-ui 에 있습니다.

flutter-codelabs/firebase-auth-flutterfire-ui 디렉터리에는 두 개의 Flutter 프로젝트가 포함되어 있습니다. 하나는 complete 라고 하고 다른 하나는 start 이라고 합니다. start 디렉터리에는 불완전한 프로젝트가 포함되어 있으며 여기서 가장 많은 시간을 보내게 됩니다.

cd flutter-codelabs/firebase-auth-flutterfire-ui/start

앞으로 건너뛰거나 완료 시 어떤 모습일지 확인하려면 상호 참조를 위해 완료라는 디렉터리를 살펴보세요.

Codelab을 따라하면서 코드를 직접 추가하려면 flutter-codelabs/firebase-auth-flutterfire-ui/start 에서 Flutter 앱으로 시작하고 Codelab 전체에서 해당 프로젝트에 코드를 추가해야 합니다. 해당 디렉터리를 원하는 IDE로 열거나 가져옵니다.

Firebase CLI 설치

Firebase CLI는 Firebase 프로젝트 관리를 위한 도구를 제공합니다. FlutterFire CLI에는 CLI가 필요하며 잠시 후에 설치하게 됩니다.

CLI를 설치하는 방법은 다양합니다. MacOS 또는 Linux를 사용하는 경우 가장 간단한 방법은 터미널에서 다음 명령을 실행하는 것입니다.

curl -sL https://firebase.tools | bash

CLI를 설치한 후 Firebase에 인증해야 합니다.

  1. 다음 명령을 실행하여 Google 계정을 사용하여 Firebase에 로그인합니다.
firebase login
  1. 이 명령어는 로컬 머신을 Firebase에 연결하고 Firebase 프로젝트에 대한 액세스 권한을 부여합니다.
  1. Firebase 프로젝트를 나열하여 CLI가 제대로 설치되었고 계정에 액세스할 수 있는지 테스트하세요. 다음 명령을 실행하십시오.
firebase projects:list
  1. 표시되는 목록은 Firebase 콘솔 에 나열된 Firebase 프로젝트와 동일해야 합니다. 최소한 flutterfire-ui-codelab.

FlutterFire CLI 설치

FlutterFire CLI는 Flutter 앱에서 지원되는 모든 플랫폼에서 Firebase 설치 프로세스를 쉽게 해주는 도구입니다. Firebase CLI를 기반으로 구축되었습니다.

먼저 CLI를 설치합니다.

dart pub global activate flutterfire_cli

CLI가 설치되었는지 확인하세요. 다음 명령을 실행하고 CLI가 도움말 메뉴를 출력하는지 확인합니다.

flutterfire -—help

Flutter 앱에 Firebase 프로젝트 추가

FlutterFire 구성

FlutterFire를 사용하면 Flutter 앱에서 Firebase를 사용하는 데 필요한 Dart 코드를 생성할 수 있습니다.

flutterfire configure

이 명령을 실행하면 사용할 Firebase 프로젝트와 설정할 플랫폼을 선택하라는 메시지가 표시됩니다.

다음 스크린샷은 응답해야 하는 프롬프트를 보여줍니다.

  1. 사용하려는 프로젝트를 선택하세요. 이 경우 flutterfire-ui-codelab 사용하세요. 1359cdeb83204baa.png
  2. 사용할 플랫폼을 선택하세요. 이 Codelab에는 웹, iOS, Android용 Flutter용 Firebase 인증을 구성하는 단계가 있지만 모든 옵션을 사용하도록 Firebase 프로젝트를 설정할 수 있습니다. 301c9534f594f472.png
  3. 이 스크린샷은 프로세스 마지막의 출력을 보여줍니다. Firebase에 익숙하다면 콘솔에서 플랫폼 애플리케이션(예: Android 애플리케이션)을 만들 필요가 없었고 FlutterFire CLI가 이를 대신했다는 것을 알 수 있을 것입니다. 12199a85ade30459.png

이 작업이 완료되면 텍스트 편집기에서 Flutter 앱을 살펴보세요. FlutterFire CLI는 firebase_options.dart 라는 새 파일을 생성했습니다. 이 파일에는 각 플랫폼에 필요한 Firebase 구성을 보유하는 정적 변수가 있는 FirebaseOptions라는 클래스가 포함되어 있습니다. flutterfire configure 실행할 때 모든 플랫폼을 선택한 경우 web , android , iosmacos 라는 정적 값이 표시됩니다.

firebase_options.dart

import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
import 'package:flutter/foundation.dart'
   show defaultTargetPlatform, kIsWeb, TargetPlatform;

/// Default [FirebaseOptions] for use with your Firebase apps.
///
/// Example:
/// ```dart
/// import 'firebase_options.dart';
/// // ...
/// await Firebase.initializeApp(
///   options: DefaultFirebaseOptions.currentPlatform,
/// );
/// ```
class DefaultFirebaseOptions {
 static FirebaseOptions get currentPlatform {
   if (kIsWeb) {
     return web;
   }
   // ignore: missing_enum_constant_in_switch
   switch (defaultTargetPlatform) {
     case TargetPlatform.android:
       return android;
     case TargetPlatform.iOS:
       return ios;
     case TargetPlatform.macOS:
       return macos;
   }

   throw UnsupportedError(
     'DefaultFirebaseOptions are not supported for this platform.',
   );
 }

 static const FirebaseOptions web = FirebaseOptions(
   apiKey: 'AIzaSyCqFjCV_9CZmYeIvcK9FVy4drmKUlSaIWY',
   appId: '1:963656261848:web:7219f7fca5fc70afb237ad',
   messagingSenderId: '963656261848',
   projectId: 'flutterfire-ui-codelab',
   authDomain: 'flutterfire-ui-codelab.firebaseapp.com',
   storageBucket: 'flutterfire-ui-codelab.appspot.com',
   measurementId: 'G-DGF0CP099H',
 );

 static const FirebaseOptions android = FirebaseOptions(
   apiKey: 'AIzaSyDconZaCQpkxIJ5KQBF-3tEU0rxYsLkIe8',
   appId: '1:963656261848:android:c939ccc86ab2dcdbb237ad',
   messagingSenderId: '963656261848',
   projectId: 'flutterfire-ui-codelab',
   storageBucket: 'flutterfire-ui-codelab.appspot.com',
 );

 static const FirebaseOptions ios = FirebaseOptions(
   apiKey: 'AIzaSyBqLWsqFjYAdGyihKTahMRDQMo0N6NVjAs',
   appId: '1:963656261848:ios:d9e01cfe8b675dfcb237ad',
   messagingSenderId: '963656261848',
   projectId: 'flutterfire-ui-codelab',
   storageBucket: 'flutterfire-ui-codelab.appspot.com',
   iosClientId: '963656261848-v7r3vq1v6haupv0l1mdrmsf56ktnua60.apps.googleusercontent.com',
   iosBundleId: 'com.example.complete',
 );

 static const FirebaseOptions macos = FirebaseOptions(
   apiKey: 'AIzaSyBqLWsqFjYAdGyihKTahMRDQMo0N6NVjAs',
   appId: '1:963656261848:ios:d9e01cfe8b675dfcb237ad',
   messagingSenderId: '963656261848',
   projectId: 'flutterfire-ui-codelab',
   storageBucket: 'flutterfire-ui-codelab.appspot.com',
   iosClientId: '963656261848-v7r3vq1v6haupv0l1mdrmsf56ktnua60.apps.googleusercontent.com',
   iosBundleId: 'com.example.complete',
 );
}

Firebase는 애플리케이션이라는 단어를 사용하여 Firebase 프로젝트의 특정 플랫폼에 대한 특정 빌드를 나타냅니다. 예를 들어 FlutterFire-ui-codelab이라는 Firebase 프로젝트에는 Android용, iOS용, MacOS용, 웹용 등 여러 애플리케이션이 있습니다.

DefaultFirebaseOptions.currentPlatform 메소드는 Flutter에서 노출된 TargetPlatform 열거형을 사용하여 앱이 실행 중인 플랫폼을 감지한 다음 올바른 Firebase 애플리케이션에 필요한 Firebase 구성 값을 반환합니다.

Flutter 앱에 Firebase 패키지 추가

마지막 설정 단계는 관련 Firebase 패키지를 Flutter 프로젝트에 추가하는 것입니다. firebase_options.dart 파일은 아직 추가되지 않은 Firebase 패키지에 의존하기 때문에 오류가 있어야 합니다. 터미널에서 flutter-codelabs/firebase-emulator-suite/start 에 있는 Flutter 프로젝트의 루트에 있는지 확인하세요. 그런 다음 다음 세 가지 명령을 실행합니다.

flutter pub add firebase_core
flutter pub add firebase_auth
flutter pub add firebase_ui_auth

이 시점에서 필요한 유일한 패키지는 다음과 같습니다.

Firebase 초기화

추가된 패키지와 DefaultFirebaseOptions.currentPlatform, 사용하려면 main.dart 파일의 main 함수 코드를 업데이트하세요.

메인.다트

void main() async {
 WidgetsFlutterBinding.ensureInitialized();
 await Firebase.initializeApp(
   options: DefaultFirebaseOptions.currentPlatform,
 );


 runApp(const MyApp());
}

이 코드는 두 가지 작업을 수행합니다.

  1. WidgetsFlutterBinding.ensureInitialized() 는 Flutter 프레임워크가 완전히 부팅될 때까지 애플리케이션 위젯 코드 실행을 시작하지 않도록 Flutter에 지시합니다. Firebase는 프레임워크를 실행해야 하는 기본 플랫폼 채널을 사용합니다.
  2. Firebase.initializeApp Flutter 앱과 Firebase 프로젝트 간의 연결을 설정합니다. DefaultFirebaseOptions.currentPlatform 은 생성된 firebase_options.dart 파일에서 가져옵니다. 이 정적 값은 실행 중인 플랫폼을 감지하고 해당 Firebase 키를 전달합니다.

4. 초기 Firebase UI 인증 페이지 추가

인증용 Firebase UI는 애플리케이션의 전체 화면을 나타내는 위젯을 제공합니다. 이러한 화면은 로그인, 등록, 비밀번호 찾기, 사용자 프로필 등과 같은 애플리케이션 전체의 다양한 인증 흐름을 처리합니다. 시작하려면 기본 애플리케이션에 대한 인증 가드 역할을 하는 랜딩 페이지를 앱에 추가하세요.

머티리얼 또는 Cupertino 앱

FlutterFire UI에서는 애플리케이션이 MaterialApp 또는 CupertinoApp으로 래핑되어야 합니다. 선택에 따라 UI는 Material 또는 Cupertino 위젯의 차이점을 자동으로 반영합니다. 이 Codelab에서는 app.dart 의 앱에 이미 추가된 MaterialApp 사용합니다.

앱.다트

import 'package:flutter/material.dart';
import 'auth_gate.dart';

class MyApp extends StatelessWidget {
 const MyApp({super.key});
 @override
 Widget build(BuildContext context) {
   return MaterialApp(
     theme: ThemeData(
       primarySwatch: Colors.blue,
     ),
     home: const AuthGate(),
   );
 }
}

인증 상태 확인

로그인 화면을 표시하려면 먼저 사용자가 현재 인증되었는지 확인해야 합니다. 이를 확인하는 가장 일반적인 방법은 Firebase 인증 플러그인을 사용하여 FirebaseAuth의 authStateChanges를 수신하는 것입니다.

위의 코드 샘플에서 MaterialApp 빌드 메소드에서 AuthGate 위젯을 빌드하고 있습니다. (FlutterFire UI에서 제공하지 않는 커스텀 위젯입니다.)

authStateChanges 스트림을 포함하도록 해당 위젯을 업데이트해야 합니다.

authStateChanges API는 현재 사용자(로그인한 경우) 또는 로그인하지 않은 경우 null을 포함하는 Stream 반환합니다. 애플리케이션에서 이 상태를 구독하려면 Flutter의 StreamBuilder 위젯을 사용하여 스트림을 전달하면 됩니다.

StreamBuilder 전달한 스트림 의 최신 데이터 스냅샷을 기반으로 자체적으로 빌드되는 위젯입니다. Stream이 새 스냅샷을 생성하면 자동으로 다시 빌드됩니다.

auth_gate.dart 의 코드를 업데이트하세요.

auth_gate.dart

import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';

import 'home.dart';

class AuthGate extends StatelessWidget {
  const AuthGate({super.key});

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<User?>(
      stream: FirebaseAuth.instance.authStateChanges(),
      builder: (context, snapshot) {
        if (!snapshot.hasData) {
          return SignInScreen(
            providers: [],
          );
        }

        return const HomeScreen();
      },
    );
  }
}
  • StreamBuilder.stream 앞서 언급한 스트림인 FirebaseAuth.instance.authStateChanged 전달하며, 사용자가 인증된 경우 Firebase User 객체를 반환합니다. (그렇지 않으면 null 반환합니다.)
  • 다음으로 코드는 snapshot.hasData 사용하여 스트림의 값에 User 개체가 포함되어 있는지 확인합니다.
  • 없는 경우 SignInScreen 위젯이 반환됩니다. 현재 해당 화면에서는 아무 작업도 수행되지 않습니다. 이는 다음 단계에서 업데이트됩니다.
  • 그렇지 않으면 인증된 사용자만 액세스할 수 있는 애플리케이션의 주요 부분인 HomeScreen 반환합니다.

SignInScreen FlutterFire UI 패키지에서 제공되는 위젯입니다. 이것이 이 Codelab의 다음 단계의 초점이 될 것입니다. 이 시점에서 앱을 실행하면 빈 로그인 화면이 표시됩니다.

5. 로그인 화면

FlutterFire UI에서 제공하는 SignInScreen 위젯은 다음 기능을 추가합니다.

  • 사용자가 로그인하도록 허용합니다.
  • 사용자가 비밀번호를 잊어버린 경우 '비밀번호를 잊으셨나요?'를 탭하면 됩니다. 비밀번호를 재설정하는 양식으로 이동하게 됩니다.
  • 사용자가 아직 등록되지 않은 경우 "등록"을 탭하면 등록할 수 있는 다른 양식으로 이동됩니다.

다시 말하지만, 여기에는 몇 줄의 코드만 필요합니다. AuthGate 위젯의 코드를 기억해 보세요.

auth_gate.dart

import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';

import 'home.dart';

class AuthGate extends StatelessWidget {
  const AuthGate({super.key});

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<User?>(
      stream: FirebaseAuth.instance.authStateChanges(),
      builder: (context, snapshot) {
        if (!snapshot.hasData) {
          return SignInScreen(
            providers: [
              EmailAuthProvider(), // new
            ],
          );
        }

        return const HomeScreen();
      },
    );
  }
}

SignInScreen 위젯과 해당 providers 인수는 앞서 언급한 모든 기능을 얻는 데 필요한 유일한 코드입니다. 이제 '이메일' 및 '비밀번호' 텍스트 입력과 '로그인' 버튼이 있는 로그인 화면이 표시됩니다.

기능적이지만 스타일이 부족합니다. 위젯은 로그인 화면의 모양을 맞춤설정하는 매개변수를 노출합니다. 예를 들어 회사 로고를 추가할 수 있습니다.

로그인 화면 사용자 정의

헤더빌더

SignInScreen.headerBuilder 인수를 사용하면 로그인 양식 위에 원하는 위젯을 추가할 수 있습니다. 다음 코드로 auth_gate.dart 파일을 업데이트하세요.

auth_gate.dart

import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';

import 'home.dart';

class AuthGate extends StatelessWidget {
 const AuthGate({super.key});

 @override
 Widget build(BuildContext context) {
   return StreamBuilder<User?>(
     stream: FirebaseAuth.instance.authStateChanges(),
     builder: (context, snapshot) {
       if (!snapshot.hasData) {
         return SignInScreen(
           providers: [
             EmailAuthProvider(),
           ],
           headerBuilder: (context, constraints, shrinkOffset) {
             return Padding(
               padding: const EdgeInsets.all(20),
               child: AspectRatio(
                 aspectRatio: 1,
                 child: Image.asset('assets/flutterfire_300x.png'),
               ),
             );
           },
         );
       }

       return const HomeScreen();
     },
   );
 }
}

headerBuilder 인수에는 FlutterFire UI 패키지에 정의된 HeaderBuilder 유형의 함수가 필요합니다.

typedef HeaderBuilder = Widget Function(
 BuildContext context,
 BoxConstraints constraints,
 double shrinkOffset,
);

콜백이기 때문에 BuildContextBoxConstraints 와 같이 사용할 수 있는 값을 노출하고 위젯을 반환해야 합니다. 어떤 위젯을 반환하든 화면 상단에 표시됩니다. 이 예에서 새 코드는 화면 상단에 이미지를 추가합니다. 이제 애플리케이션은 다음과 같아야 합니다.

73d7548d91bbd2ab.png

자막 작성기

로그인 화면은 화면을 맞춤설정할 수 있는 세 가지 추가 매개변수( subtitleBuilder , footerBuildersideBuilder )를 노출합니다.

subtitleBuilder 는 콜백 인수에 AuthAction 유형의 작업이 포함된다는 점에서 약간 다릅니다. AuthAction 은 사용자가 있는 화면이 "로그인" 화면인지 "등록" 화면인지 감지하는 데 사용할 수 있는 열거형입니다.

subtitleBuilder를 사용하려면 auth_gate.dart의 코드를 업데이트하세요.

auth_gate.dart

import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';

import 'home.dart';

class AuthGate extends StatelessWidget {
 const AuthGate({super.key});

 @override
 Widget build(BuildContext context) {
   return StreamBuilder<User?>(
     stream: FirebaseAuth.instance.authStateChanges(),
     builder: (context, snapshot) {
       if (!snapshot.hasData) {
         return SignInScreen(
           providers: [
              EmailAuthProvider()
           ],
           headerBuilder: (context, constraints, shrinkOffset) {
             return Padding(
               padding: const EdgeInsets.all(20),
               child: AspectRatio(
                 aspectRatio: 1,
                 child: Image.asset('flutterfire_300x.png'),
               ),
             );
           },
           subtitleBuilder: (context, action) {
             return Padding(
               padding: const EdgeInsets.symmetric(vertical: 8.0),
               child: action == AuthAction.signIn
                   ? const Text('Welcome to FlutterFire, please sign in!')
                   : const Text('Welcome to Flutterfire, please sign up!'),
             );
           },
         );
       }

       return const HomeScreen();
     },
   );
 }
}

애플리케이션을 다시 로드하면 다음과 같이 표시됩니다.

footerBuilder 인수는 subtitleBuilder와 동일합니다. 이미지가 아닌 텍스트용이므로 BoxConstraints 또는 shrinkOffset 노출하지 않습니다. (원하는 위젯을 추가할 수는 있지만)

이 코드를 사용하여 로그인 화면에 바닥글을 추가하세요.

auth_gate.dart

import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';

import 'home.dart';

class AuthGate extends StatelessWidget {
 const AuthGate({super.key});

 @override
 Widget build(BuildContext context) {
   return StreamBuilder<User?>(
     stream: FirebaseAuth.instance.authStateChanges(),
     builder: (context, snapshot) {
       if (!snapshot.hasData) {
         return SignInScreen(
           providers: [
             EmailAuthProvider()
           ],
           headerBuilder: (context, constraints, shrinkOffset) {
             return Padding(
               padding: const EdgeInsets.all(20),
               child: AspectRatio(
                 aspectRatio: 1,
                 child: Image.asset('flutterfire_300x.png'),
               ),
             );
           },
           subtitleBuilder: (context, action) {
             return Padding(
               padding: const EdgeInsets.symmetric(vertical: 8.0),
               child: action == AuthAction.signIn
                   ? const Text('Welcome to FlutterFire, please sign in!')
                   : const Text('Welcome to Flutterfire, please sign up!'),
             );
           },
           footerBuilder: (context, action) {
             return const Padding(
               padding: EdgeInsets.only(top: 16),
               child: Text(
                 'By signing in, you agree to our terms and conditions.',
                 style: TextStyle(color: Colors.grey),
               ),
             );
           },
         );
       }

       return const HomeScreen();
     },
   );
 }}

사이드 빌더

SignInScreen.sidebuilder 인수는 콜백을 허용하며, 이번에는 해당 콜백에 대한 인수는 BuildContextdouble shrinkOffset 입니다. sideBuilder가 반환하는 위젯은 로그인 양식 왼쪽에 표시되며 와이드 화면에만 표시됩니다. 이는 사실상 위젯이 데스크톱 및 웹 앱에만 표시된다는 의미입니다.

내부적으로 FlutterFire UI는 중단점을 사용하여 헤더 콘텐츠를 표시해야 하는지(모바일과 같은 긴 화면에) 측면 콘텐츠를 표시해야 하는지(와이드 스크린, 데스크톱 또는 웹에) 결정합니다. 특히 화면 너비가 800픽셀을 초과하는 경우 사이드 빌더 콘텐츠가 표시되고 헤더 콘텐츠는 표시되지 않습니다. 화면 너비가 800픽셀 미만이면 그 반대입니다.

auth_gate.dart의 코드를 업데이트하여 sideBuilder 위젯을 추가하세요.

auth_gate.dart

import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';

import 'home.dart';

class AuthGate extends StatelessWidget {
 const AuthGate({super.key});

 @override
 Widget build(BuildContext context) {
   return StreamBuilder<User?>(
     stream: FirebaseAuth.instance.authStateChanges(),
     builder: (context, snapshot) {
       if (!snapshot.hasData) {
         return SignInScreen(
           providers: [
             EmailAuthProvider(),
           ],
           headerBuilder: (context, constraints, shrinkOffset) {
             return Padding(
               padding: const EdgeInsets.all(20),
               child: AspectRatio(
                 aspectRatio: 1,
                 child: Image.asset('flutterfire_300x.png'),
               ),
             );
           },
           subtitleBuilder: (context, action) {
             return Padding(
               padding: const EdgeInsets.symmetric(vertical: 8.0),
               child: action == AuthAction.signIn
                   ? const Text('Welcome to FlutterFire, please sign in!')
                   : const Text('Welcome to Flutterfire, please sign up!'),
             );
           },
           footerBuilder: (context, action) {
             return const Padding(
               padding: EdgeInsets.only(top: 16),
               child: Text(
                 'By signing in, you agree to our terms and conditions.',
                 style: TextStyle(color: Colors.grey),
               ),
             );
           },
           sideBuilder: (context, shrinkOffset) {
             return Padding(
               padding: const EdgeInsets.all(20),
               child: AspectRatio(
                 aspectRatio: 1,
                 child: Image.asset('flutterfire_300x.png'),
               ),
             );
           },
         );
       }
       return const HomeScreen();
     },
   );
 }
}

이제 창 너비를 확장하면 앱이 다음과 같이 보일 것입니다(Flutter 웹 또는 MacOS를 사용하는 경우).

8dc60b4e5d7dd2d0.png

사용자 생성

이제 이 화면의 모든 코드가 완료되었습니다. 하지만 로그인하려면 먼저 사용자를 만들어야 합니다. '등록' 화면에서 이 작업을 수행하거나 Firebase 콘솔에서 사용자를 만들 수 있습니다.

콘솔을 사용하려면:

  1. Firebase 콘솔에서 '사용자' 테이블로 이동합니다.
  2. 여기를 클릭하세요
  3. 'flutterfire-ui-codelab'(또는 다른 이름을 사용한 경우 다른 프로젝트)을 선택합니다. 다음 테이블이 표시됩니다.

f038fd9a58ed60d9.png

  1. "사용자 추가" 버튼을 클릭하세요.

2d78390d4c5dbbfa.png

  1. 새 사용자의 이메일 주소와 비밀번호를 입력하세요. 아래 이미지에 입력한 것처럼 이는 가짜 이메일과 비밀번호일 수 있습니다. 그러면 작동하지만, 가짜 이메일 주소를 사용하는 경우 "비밀번호 찾기" 기능은 작동하지 않습니다.

62ba0feb33d54add.png

  1. "사용자 추가"를 클릭하세요

32b236b3ef94d4c7.png

이제 Flutter 애플리케이션으로 돌아가서 로그인 페이지를 통해 사용자를 로그인할 수 있습니다. 앱은 다음과 같아야 합니다.

dd43d260537f3b1a.png

6. 프로필 화면

FlutterFire UI는 또한 몇 줄의 코드로 많은 기능을 제공하는 ProfileScreen 위젯도 제공합니다.

ProfileScreen 위젯 추가

텍스트 편집기에서 home.dart 파일로 이동합니다. 다음 코드로 업데이트하세요.

홈.다트

import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';

class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        actions: [
          IconButton(
            icon: const Icon(Icons.person),
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute<ProfileScreen>(
                  builder: (context) => const ProfileScreen(),
                ),
              );
            },
          )
        ],
        automaticallyImplyLeading: false,
      ),
      body: Center(
        child: Column(
          children: [
            Image.asset('dash.png'),
            Text(
              'Welcome!',
              style: Theme.of(context).textTheme.displaySmall,
            ),
            const SignOutButton(),
          ],
        ),
      ),
    );
  }
}

주목할 만한 새로운 코드는 IconButton.isPressed method. 해당 IconButton 누르면 애플리케이션이 새로운 익명 경로를 생성하고 해당 경로로 이동합니다. 해당 경로는 MaterialPageRoute.builder 콜백에서 반환되는 ProfileScreen 위젯을 표시합니다.

앱을 다시 로드하고 오른쪽 상단(앱 바)에 있는 아이콘을 누르면 다음과 같은 페이지가 표시됩니다.

36487fc4ab4f26a7.png

FlutterFire UI 페이지에서 제공하는 표준 UI입니다. 모든 버튼과 텍스트 필드는 Firebase 인증에 연결되어 있어 즉시 사용할 수 있습니다. 예를 들어 '이름' 텍스트 필드에 이름을 입력하면 FlutterFire UI가 FirebaseAuth.instance.currentUser?.updateDisplayName 메서드를 호출하여 해당 이름을 Firebase에 저장합니다.

로그아웃

지금은 '로그아웃' 버튼을 눌러도 앱이 변경되지 않습니다. 로그아웃되지만 AuthGate 위젯으로 다시 이동되지는 않습니다. 이를 구현하려면 ProfileScreen.actions 매개변수를 사용하세요.

먼저 home.dart의 코드를 업데이트하세요.

홈.다트

import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';

class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        actions: [
          IconButton(
            icon: const Icon(Icons.person),
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute<ProfileScreen>(
                  builder: (context) => ProfileScreen(
                    actions: [
                      SignedOutAction((context) {
                        Navigator.of(context).pop();
                      })
                    ],
                  ),
                ),
              );
            },
          )
        ],
        automaticallyImplyLeading: false,
      ),
      body: Center(
        child: Column(
          children: [
            Image.asset('dash.png'),
            Text(
              'Welcome!',
              style: Theme.of(context).textTheme.displaySmall,
            ),
            const SignOutButton(),
          ],
        ),
      ),
    );
  }
}

이제 ProfileScreen 인스턴스를 생성할 때 ProfileScreen.actions 인수에 작업 목록도 전달합니다. 이러한 작업은 FlutterFireUiAction 유형입니다. FlutterFireUiAction 의 하위 유형인 다양한 클래스가 있으며 일반적으로 이를 사용하여 앱이 다양한 인증 상태 변경에 반응하도록 지시합니다. SignedOutAction은 Firebase 인증 상태가 currentUser가 null로 변경될 때 제공하는 콜백 함수를 호출합니다.

SignedOutAction이 트리거될 때 Navigator.of(context).pop() 호출하는 콜백을 추가하면 앱이 이전 페이지로 이동합니다. 이 예제 앱에는 로그인한 사용자가 없는 경우 로그인 페이지를 표시하고 사용자가 있는 경우 홈 페이지를 표시하는 영구 경로가 하나만 있습니다. 이는 사용자가 로그아웃할 때 발생하므로 앱에 로그인 페이지가 표시됩니다.

프로필 페이지 사용자 정의

로그인 페이지와 유사하게 프로필 페이지를 사용자 정의할 수 있습니다. 첫째, 현재 페이지에는 사용자가 프로필 페이지에 있으면 홈 페이지로 다시 이동할 수 있는 방법이 없습니다. ProfileScreen 위젯에 AppBar를 제공하여 이 문제를 해결하세요.

홈.다트

import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';

class HomeScreen extends StatelessWidget {
 const HomeScreen({super.key});

 @override
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(
       actions: [
         IconButton(
           icon: const Icon(Icons.person),
           onPressed: () {
             Navigator.push(
               context,
               MaterialPageRoute<ProfileScreen>(
                 builder: (context) => ProfileScreen(
                   appBar: AppBar(
                     title: const Text('User Profile'),
                   ),
                   actions: [
                     SignedOutAction((context) {
                       Navigator.of(context).pop();
                     })
                   ],
                 ),
               ),
             );
           },
         )
       ],
       automaticallyImplyLeading: false,
     ),
     body: Center(
       child: Column(
         children: [
           Image.asset('dash.png'),
           Text(
             'Welcome!',
             style: Theme.of(context).textTheme.displaySmall,
           ),
           const SignOutButton(),
         ],
       ),
     ),
   );
 }
}

ProfileScreen.appBar 인수는 Flutter Material 패키지의 AppBar 위젯을 허용하므로 이를 빌드하여 Scaffold 에 전달한 다른 AppBar 처럼 처리할 수 있습니다. 이 예에서는 "뒤로" 버튼을 자동으로 추가하는 기본 기능이 유지되며 이제 화면에 제목이 있습니다.

프로필 화면에 자녀 추가

ProfileScreen 위젯에는 children이라는 선택적 인수도 있습니다. 이 인수는 위젯 목록을 허용하며 해당 위젯은 이미 ProfileScreen을 구축하기 위해 내부적으로 사용되는 Column 위젯 내부에 수직으로 배치됩니다. ProfileScreen 빌드 메소드의 이 열 위젯은 전달한 하위 항목을 "로그아웃" 버튼 위에 배치합니다.

로그인 화면과 비슷하게 여기에 회사 로고를 표시하려면 home.dart의 코드를 업데이트하세요.

홈.다트

import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';

class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        actions: [
          IconButton(
            icon: const Icon(Icons.person),
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute<ProfileScreen>(
                  builder: (context) => ProfileScreen(
                    appBar: AppBar(
                      title: const Text('User Profile'),
                    ),
                    actions: [
                      SignedOutAction((context) {
                        Navigator.of(context).pop();
                      })
                    ],
                    children: [
                      const Divider(),
                      Padding(
                        padding: const EdgeInsets.all(2),
                        child: AspectRatio(
                          aspectRatio: 1,
                          child: Image.asset('flutterfire_300x.png'),
                        ),
                      ),
                    ],
                  ),
                ),
              );
            },
          )
        ],
        automaticallyImplyLeading: false,
      ),
      body: Center(
        child: Column(
          children: [
            Image.asset('dash.png'),
            Text(
              'Welcome!',
              style: Theme.of(context).textTheme.displaySmall,
            ),
            const SignOutButton(),
          ],
        ),
      ),
    );
  }
}

앱을 다시 로드하면 화면에 다음이 표시됩니다.

ebe5792b765dbf87.png

7. 다중 플랫폼 Google 인증 로그인

FlutterFire UI는 Google, Twitter, Facebook, Apple, Github와 같은 타사 제공업체를 인증하기 위한 위젯과 기능도 제공합니다.

Google 인증과 통합하려면 기본 인증 흐름을 처리할 공식 firebase_ui_oauth_google 플러그인과 해당 종속성을 설치하세요. 터미널에서 Flutter 프로젝트의 루트로 이동하여 다음 명령을 입력하세요.

flutter pub add google_sign_in
flutter pub add firebase_ui_oauth_google

Google 로그인 제공업체 활성화

다음으로 Firebase 콘솔 에서 Google 공급자를 활성화합니다.

  1. 콘솔에서 인증 로그인 공급자 화면으로 이동합니다.
  2. "새 공급자 추가"를 클릭하세요. 8286fb28be94bf30.png
  3. "구글"을 선택하세요. c4e28e6f4974be7f.png
  4. "활성화"라고 표시된 스위치를 전환하고 "저장"을 누릅니다. e74ff86990763826.png
  5. 구성 파일 다운로드에 대한 정보가 포함된 모달이 나타나면 "완료"를 클릭하세요.
  6. Google 로그인 제공업체가 추가되었는지 확인하세요. 5329ce0543c90d95.png

Google 로그인 버튼 추가

Google 로그인이 활성화된 상태에서 로그인 페이지에 스타일화된 Google 로그인 버튼을 표시하는 데 필요한 위젯을 추가하세요. auth_gate.dart 파일로 이동하여 코드를 다음과 같이 업데이트합니다.

auth_gate.dart

import 'package:firebase_auth/firebase_auth.dart' hide EmailAuthProvider;
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:firebase_ui_oauth_google/firebase_ui_oauth_google.dart'; // new
import 'package:flutter/material.dart';

import 'home.dart';

class AuthGate extends StatelessWidget {
 const AuthGate({super.key});

 @override
 Widget build(BuildContext context) {
   return StreamBuilder<User?>(
     stream: FirebaseAuth.instance.authStateChanges(),
     builder: (context, snapshot) {
       if (!snapshot.hasData) {
         return SignInScreen(
           providers: [
             EmailAuthProvider(),
             GoogleProvider(clientId: "YOUR_WEBCLIENT_ID"),  // new
           ],
           headerBuilder: (context, constraints, shrinkOffset) {
             return Padding(
               padding: const EdgeInsets.all(20),
               child: AspectRatio(
                 aspectRatio: 1,
                 child: Image.asset('flutterfire_300x.png'),
               ),
             );
           },
           subtitleBuilder: (context, action) {
             return Padding(
               padding: const EdgeInsets.symmetric(vertical: 8.0),
               child: action == AuthAction.signIn
                   ? const Text('Welcome to FlutterFire, please sign in!')
                   : const Text('Welcome to Flutterfire, please sign up!'),
             );
           },
           footerBuilder: (context, action) {
             return const Padding(
               padding: EdgeInsets.only(top: 16),
               child: Text(
                 'By signing in, you agree to our terms and conditions.',
                 style: TextStyle(color: Colors.grey),
               ),
             );
           },
           sideBuilder: (context, shrinkOffset) {
             return Padding(
               padding: const EdgeInsets.all(20),
               child: AspectRatio(
                 aspectRatio: 1,
                 child: Image.asset('flutterfire_300x.png'),
               ),
             );
           },
         );
       }

       return const HomeScreen();
     },
   );
 }
}

여기서 유일한 새로운 코드는 SignInScreen 위젯 구성에 GoogleProvider(clientId: "YOUR_WEBCLIENT_ID") 추가하는 것입니다.

이를 추가한 후 앱을 다시 로드하면 Google 로그인 버튼이 표시됩니다.

aca71a46a011bfb5.png

로그인 버튼 구성

추가 구성 없이는 버튼이 작동하지 않습니다. Flutter Web으로 개발하는 경우 이것이 작동하려면 추가해야 하는 유일한 단계입니다. 다른 플랫폼에는 추가 단계가 필요하며 이에 대해서는 잠시 후에 설명하겠습니다.

  1. Firebase 콘솔 에서 인증 제공업체 페이지로 이동합니다.
  2. Google 제공업체를 클릭하세요. 9b3a325c5eca6e49.png
  3. "웹 SDK 구성" 확장 패널을 클릭합니다.
  4. '웹 클라이언트 ID'에서 값을 복사합니다. 711a79f0d931c60f.png
  5. 텍스트 편집기로 돌아가서 이 ID를 매개변수라는 clientId 에 전달하여 auth_gate.dart 파일에서 GoogleProvider 인스턴스를 업데이트합니다.
GoogleProvider(
   clientId: "YOUR_WEBCLIENT_ID"
)

웹 클라이언트 ID를 입력한 후 앱을 다시 로드하세요. 'Google로 로그인' 버튼을 누르면 Google 로그인 과정을 안내하는 새 창이 나타납니다(웹을 사용하는 경우). 처음에는 다음과 같습니다.

14e73e3c9de704bb.png

iOS 구성

iOS에서 작동하려면 추가 구성 프로세스가 필요합니다.

  1. Firebase 콘솔 의 프로젝트 설정 화면으로 이동합니다. 다음과 같은 Firebase 앱 목록이 포함된 카드가 있습니다. fefa674acbf213cc.png
  2. iOS를 클릭하세요. 귀하의 애플리케이션 이름은 내 것과 다를 수 있습니다. 이 Codelab을 따르기 위해 flutter-codelabs/firebase-auth-flutterfire-ui/start 프로젝트를 사용했다면 내 프로젝트가 '완료'라고 표시되어 있으면 귀하의 프로젝트는 '시작'이라고 표시됩니다.
  3. 필요한 구성 파일을 다운로드하려면 "GoogleServices-Info.plist" 버튼을 클릭하세요. f89b3192871dfbe3.png
  4. 다운로드한 파일을 이라는 디렉토리에 끌어다 놓습니다. Flutter 프로젝트의 /ios/Runner .
  5. 프로젝트 루트에서 다음 터미널 명령을 실행하여 Xcode를 엽니다.

iOS/Runner.xcworkspace를 엽니다.

  1. Runner 디렉터리를 마우스 오른쪽 버튼으로 클릭하고 "Runner"에 파일 추가를 선택합니다. 858986063a4c5201.png
  2. 파일 관리자에서 GoogleService-Info.plist를 선택합니다.
  3. Xcode가 아닌 텍스트 편집기로 돌아가서 아래 CFBundleURLTypes 속성을 [my_project]/ios/Runner/Info.plist 파일에 추가하세요.
<!-- Put me in the [my_project]/ios/Runner/Info.plist file -->
<!-- Google Sign-in Section -->
<key>CFBundleURLTypes</key>
<array>
        <dict>
                <key>CFBundleTypeRole</key>
                <string>Editor</string>
                <key>CFBundleURLSchemes</key>
                <array>
                        <!-- TODO Replace this value: -->
                        <!-- Copied from GoogleService-Info.plist key REVERSED_CLIENT_ID -->
                        <string>com.googleusercontent.apps.861823949799-vc35cprkp249096uujjn0vvnmcvjppkn</string>
                </array>
        </dict>
</array>
<!-- End of the Google Sign-in Section -->

Flutter 앱이 이미 iOS에서 실행되고 있다면 앱을 완전히 종료한 다음 애플리케이션을 다시 실행해야 합니다. 그렇지 않으면 iOS에서 앱을 실행하세요.

8. 축하합니다!

Flutter Codelab용 Firebase 인증 UI를 완료했습니다. 이 Codelab의 완성된 코드는 github의 'complete' 디렉터리( Flutter Codelabs) 에서 찾을 수 있습니다.

우리가 다룬 내용

  • Firebase를 사용하도록 Flutter 앱 설정
  • Firebase 콘솔에서 Firebase 프로젝트 설정
  • FlutterFire CLI
  • 파이어베이스 CLI
  • Firebase 인증 사용
  • FlutterFire UI를 사용하여 Flutter 앱에서 Firebase 인증을 쉽게 처리

다음 단계

더 알아보기

Sparky가 여러분과 함께 축하하기 위해 왔습니다!

2a0ad195769368b1.gif