프로젝트를 하면서 필수적으로 구현하는 것이 로그인 기능이다. 그 중에서 가장 자주쓰면서 기본적이고 쉽게 만들 수 있는 것이 구글 로그인이다. 구현하는 방법은 파이어베이스를 통해 이루어진다.
먼저 Firebase와 Flutter 프로젝트를 Riverpod으로 관리하기 위해 필요한 패키지를 설치하자.
flutter pub add firebase_core # Firebase 초기화를 위한 필수 패키지
flutter pub add firebase_auth # Firebase 인증 (로그인/회원가입) 기능을 위한 패키지
flutter pub add google_sign_in # Google 계정으로 로그인하기 위한 Google SDK 연동 패키지
flutter pub add cloud_firestore # Firestore 데이터베이스에 접근하고 읽고 쓰기 위한 패키지
flutter pub add flutter_riverpod # 상태 관리를 위한 Riverpod 라이브러리
void main() async {
WidgetsFlutterBinding.ensureInitialized(); // 비동기 초기화를 위한 바인딩 (필수)
await Firebase.initializeApp(); // Firebase 초기화 (필수)
runApp(const ProviderScope(child: MyApp())); // 앱 실행 + Riverpod ProviderScope 전역 상태 관리 컨테이너 등록
}
WidgetsFlutterBinding.ensureInitialized();await Firebase.initializeApp();
runApp(const ProviderScope(child: MyApp()));
## 로그인 관련 서비스 구현
구글 로그인 → Firebase Auth → 유저 정보 Firestore 저장
```dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
/// Google 로그인 → Firebase 인증 → Firestore 유저 저장을 담당하는 서비스 클래스
class AuthService {
final _auth = FirebaseAuth.instance; // Firebase 인증 인스턴스
final _firestore = FirebaseFirestore.instance; // Firestore 인스턴스
/// Google 계정으로 로그인하는 메서드
Future<User?> signInWithGoogle() async {
try {
// 1. 사용자에게 Google 계정 선택 UI를 보여주고, 선택된 계정 정보를 가져옴
final googleUser = await GoogleSignIn().signIn();
if (googleUser == null) return null; // 사용자가 취소했을 경우
// 2. 인증 토큰(access token + id token)을 가져옴
final googleAuth = await googleUser.authentication;
// 3. Firebase에서 사용할 수 있는 Google 인증 자격 정보 생성
final credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
// 4. FirebaseAuth에 Google 자격 증명을 넘겨 로그인 처리
final userCredential = await _auth.signInWithCredential(credential);
final user = userCredential.user; // 로그인된 사용자 정보
if (user == null) return null;
// 5. Firestore에 사용자 정보 저장 (이미 존재하면 merge)
await _firestore.collection('users').doc(user.uid).set({
'userId': user.uid,
'displayName': user.displayName ?? '',
'photoUrl': user.photoURL ?? '',
'loginProviders': user.providerData.map((e) => e.providerId).toList(),
'createdAt': FieldValue.serverTimestamp(),
}, SetOptions(merge: true));
// 6. 로그인된 Firebase 사용자 반환
return user;
} catch (e) {
print('Login Error: $e'); // 오류 출력
return null; // 실패 시 null 반환
}
}
}
/// Riverpod Provider로 AuthService를 전역에서 사용할 수 있게 등록
final authServiceProvider = Provider((ref) => AuthService());
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:your_project_name/core/service/auth_service.dart';
/// Google 로그인 버튼을 포함한 로그인 화면 위젯
class LoginScreen extends ConsumerWidget {
const LoginScreen({super.key});
Widget build(BuildContext context, WidgetRef ref) {
// Provider에서 AuthService 인스턴스를 읽어옴
final authService = ref.read(authServiceProvider);
return Scaffold(
appBar: AppBar(title: const Text('로그인')), // 상단 앱바
body: Center(
child: ElevatedButton.icon(
onPressed: () async {
// 버튼을 누르면 로그인 시도
final user = await authService.signInWithGoogle();
if (user != null) {
// 로그인 성공 시 환영 메시지 출력
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('환영합니다, ${user.displayName}!')),
);
// TODO: 홈 화면 등으로 이동
}
},
icon: const Icon(Icons.login), // 버튼 왼쪽 아이콘
label: const Text('Google로 로그인'), // 버튼 텍스트
),
),
);
}
}
이 외에 유저 모델을 만들어서 구글 로그인이 성공한 것을 바탕으로 Firebase에 저장해야한다. 아래는 예시이며 최종코드가 아니다.
/// Google 로그인 실행 후 Firestore에 사용자 데이터 저장
Future<UserCredential?> signInWithGoogle() async {
final userCredential = await _authService.signInWithGoogle();
final user = userCredential?.user;
}
//최초 로그인시 파이어스토어에 저장
if (user != null) {
final userModel = UserModel(
userId: user.uid,
displayName: user.displayName ?? 'NoName',
email: user.email ?? 'unknown@email.com',
photoUrl: user.photoURL ?? '',
loginProviders: 'google',
);