카테고리 없음

[Expo]Firebase 연동 및 Google 로그인 구현 과정

민이(MInE) 2025. 4. 20. 01:00
반응형

Firebase를 활용한 프로젝트에서 인증 시스템을 구현하는 과정은 몇 가지 단계로 나눌 수 있습니다. 특히 에뮬레이터를 사용하여 개발 비용 없이 테스트 환경을 구축하는 것은 중요한 접근 방식입니다.

1. Firebase 초기화 설정

Firebase 서비스를 사용하기 위한 초기화 설정은 다음과 같이 구현했습니다

import {getApp, initializeApp} from '@react-native-firebase/app';
import { getAuth, connectAuthEmulator } from '@react-native-firebase/auth';
import { getFirestore, connectFirestoreEmulator } from '@react-native-firebase/firestore';
import { getStorage, connectStorageEmulator } from '@react-native-firebase/storage';

const app = getApp();
const auth = getAuth(app);
const firestore = getFirestore(app);
const storage = getStorage(app);

if (__DEV__) {
  connectAuthEmulator(auth, 'http://localhost:9099');
  connectFirestoreEmulator(firestore, 'localhost', 8080);
  connectStorageEmulator(storage, 'localhost', 9199);
  console.log('Firebase 에뮬레이터에 연결되었습니다.');
}

export { auth, firestore, storage };

이 코드는 Firebase의 주요 서비스(인증, Firestore, 스토리지)를 초기화하고, 개발 환경에서는 로컬 에뮬레이터에 연결하도록 구성됩니다. 에뮬레이터를 사용하면 실제 Firebase 비용 없이 개발 및 테스트가 가능합니다.

2. Google 로그인 구현

Google 로그인 기능은 @react-native-google-signin/google-signin 라이브러리를 활용하여 다음과 같이 구현했습니다

import { GoogleSignin, statusCodes } from '@react-native-google-signin/google-signin';
import { auth } from '../firebase/firebase';
import { GoogleAuthProvider } from '@react-native-firebase/auth';

// Google 로그인 초기화 (앱 시작 시 한 번만 호출)
export const configureGoogleSignIn = () => {
    GoogleSignin.configure({
        webClientId: "123935749466-0pos7sor5ufgmo0h9f9u32nl9mlk03ui.apps.googleusercontent.com", // 웹 클라이언트 ID
        iosClientId: '123935749466-be4k50efmaeeme69q0o10tmpi5s1cs9l.apps.googleusercontent.com', // iOS 클라이언트 ID
        offlineAccess: false, // 오프라인 액세스가 필요하지 않음
        scopes: ['profile', 'email'] // 기본 스코프
    });
};

// Google 로그인
export const signInWithGoogle = async () => {
    try {
        // Google Play 서비스 확인 (Android 전용)
        await GoogleSignin.hasPlayServices({ showPlayServicesUpdateDialog: true });

        // Google 로그인 수행
        const userInfo = await GoogleSignin.signIn();
        console.log('Google 로그인 성공:', userInfo);

        // ID 토큰 확인
        if (!userInfo.data?.idToken) {
            throw new Error('Google에서 ID 토큰을 받지 못했습니다.');
        }

        // Firebase 인증에 사용할 Google 크레덴셜 생성
        const googleCredential = GoogleAuthProvider.credential(userInfo.data.idToken);

        // Firebase로 로그인
        const userCredential = await auth.signInWithCredential(googleCredential);
        console.log('Firebase 로그인 성공:', userCredential.user.uid);

        return { user: userCredential.user, error: null };
    } catch (error: any) {
        console.error('Google 로그인 에러:', error);

        // 에러 코드에 따른 처리
        if (error.code) {
            switch (error.code) {
                case statusCodes.SIGN_IN_CANCELLED:
                    return { user: null, error: new Error('로그인이 취소되었습니다.') };
                case statusCodes.IN_PROGRESS:
                    return { user: null, error: new Error('로그인이 이미 진행 중입니다.') };
                case statusCodes.PLAY_SERVICES_NOT_AVAILABLE:
                    return { user: null, error: new Error('Google Play 서비스를 사용할 수 없습니다.') };
                default:
                    return { user: null, error: new Error(`Google 로그인 오류: ${error.message}`) };
            }
        }

        return { user: null, error };
    }
};

이 코드는 Google 로그인 과정을 처리하며, 성공 시 Firebase 인증까지 완료합니다. 또한 다양한 오류 상황에 대한 처리도 포함되어 있습니다.

3. 테스트 계정 로그인 구현

개발 환경에서는 Google 로그인 대신 테스트 계정을 사용할 수 있도록 다음 기능을 구현했습니다

// 테스트 계정 로그인 (개발 환경용)
export const signInWithTestAccount = async () => {
    try {
        console.log("테스트 계정으로 로그인 시도...");
        const testEmail = "test@example.com";
        const testPassword = "password";

        try {
            // 기존 테스트 계정으로 로그인 시도
            await auth.signInWithEmailAndPassword(testEmail, testPassword);
            console.log("테스트 계정 로그인 성공");
            return { user: auth.currentUser, error: null };
        } catch (loginError) {
            console.log("테스트 계정이 없어 새로 생성합니다", loginError);
            // 계정이 없으면 새로 생성
            const userCredential = await auth.createUserWithEmailAndPassword(
                testEmail,
                testPassword
            );
            console.log("테스트 계정 생성 및 로그인 성공");
            return { user: userCredential.user, error: null };
        }
    } catch (error) {
        console.error("테스트 로그인 에러:", error);
        return {
            user: null,
            error: new Error("Firebase 에뮬레이터에 연결되어 있는지 확인하세요.")
        };
    }
};

이 기능은 Firebase 에뮬레이터에서 테스트 계정으로 로그인하거나, 계정이 없는 경우 새로 생성하는 로직을 포함합니다. 개발 과정에서 실제 Google 계정 없이도 인증 기능을 테스트할 수 있어 유용합니다.

4. 추가 인증 관련 기능

로그인 외에도 자동 로그인, 로그아웃, 상태 확인 등의 기능을 다음과 같이 구현했습니다

// 자동 로그인 시도 (이전 로그인 정보 사용)
export const signInSilently = async () => {
    try {
        // 이전에 로그인한 사용자가 있는지 확인
        const isSignedIn = GoogleSignin.getCurrentUser();

        if (!isSignedIn) {
            return { user: null, error: null };
        }

        // 자동 로그인 시도
        const userInfo = await GoogleSignin.signInSilently();
        console.log('자동 로그인 성공:', userInfo);

        // ID 토큰으로 Firebase 로그인
        if (userInfo.data?.idToken) {
            const googleCredential = GoogleAuthProvider.credential(userInfo.data.idToken);
            const userCredential = await auth.signInWithCredential(googleCredential);
            return { user: userCredential.user, error: null };
        } else {
            // ID 토큰이 없는 경우 Firebase 로그인 불가능
            return { user: null, error: new Error('ID 토큰이 없습니다.') };
        }
    } catch (error: any) {
        console.error('자동 로그인 에러:', error);

        // 특정 에러 코드에 대한 처리
        if (error.code === statusCodes.SIGN_IN_REQUIRED) {
            // 사용자가 직접 로그인해야 함
            return { user: null, error: null };
        }

        return { user: null, error };
    }
};

// 로그아웃
export const signOut = async () => {
    try {
        // Google 로그인 로그아웃
        await GoogleSignin.signOut();

        // Firebase 로그아웃
        await auth.signOut();
        console.log('로그아웃 성공');

        return { success: true, error: null };
    } catch (error) {
        console.error('로그아웃 에러:', error);
        return { success: false, error };
    }
};

// 현재 로그인 상태 확인
export const getCurrentUser = () => {
    return auth.currentUser;
};

// 로그인 상태 변경 리스너
export const onAuthStateChanged = (callback: (user: any) => void) => {
    return auth.onAuthStateChanged(callback);
};

// Google 연결 해제 (선택 사항)
export const revokeAccess = async () => {
    try {
        await GoogleSignin.revokeAccess();
        await auth.signOut();
        console.log('Google 연결 해제 및 로그아웃 성공');
        return { success: true, error: null };
    } catch (error) {
        console.error('Google 연결 해제 에러:', error);
        return { success: false, error };
    }
};

이러한 기능들은 사용자 경험을 향상시키고, 다양한 인증 시나리오에 대응할 수 있게 해줍니다.

결론

Firebase 에뮬레이터와 Google 로그인 기능을 통합하여 비용 효율적이고 안정적인 인증 시스템을 구축할 수 있었습니다. 개발 환경에서는 테스트 계정을, 프로덕션 환경에서는 실제 Google 계정을 사용하는 유연한 접근 방식을 통해 개발 및 테스트 과정이 원활해졌습니다.

 

 

https://react-native-google-signin.github.io/docs/setting-up/expo

 

Expo setup | React Native Google Sign In

Prepare your Expo project

react-native-google-signin.github.io

https://react-native-google-signin.github.io/docs/original

 

Original Google sign in | React Native Google Sign In

To migrate to Universal sign in, follow this guide.

react-native-google-signin.github.io

https://rnfirebase.io/#prerequisites

 

React Native Firebase | React Native Firebase

Welcome to React Native Firebase! To get started, you must first setup a Firebase project and install the "app" module. React Native Firebase has begun to deprecate the namespaced API (i.e firebase-js-sdk < v9 chaining API). React Native Firebase will be m

rnfirebase.io

 

반응형