[firebase] authentication➀ 구글 로그인 연동하기

이민선(Jasmine)·2023년 3월 4일
0
post-thumbnail

저번 시간에 내가 만든 앱 호스팅하는 방법을 알아봤다.
이제부터는 구글 로그인, 이메일 로그인 이렇게 2가지를 구현 연습해보려고 한다.
이번 시간에는 firebase를 이용하여 구글 로그인을 구현한 과정을 포스팅하려고 한다.

저번 시간에 추가했던 learn-firebase 프로젝트 클릭 → 왼쪽에 authentication 클릭

시작하기 클릭!

나는 초보자이므로 구글 하나로만 우선 도전을 시작해본다.(비장) 구글 클릭!

사용설정 toggle button 클릭 → 프로젝트 지원 이메일에 나의 이메일 입력하기 → 저장

짜잔! 사용 설정되었다고 뜬다~~
좌측에 프로젝트 개요 옆에 톱니바퀴 → 프로젝트 설정 클릭!

스크롤을 내리면 내 앱 하단에

const firebaseConfig = {
.
.
.
.
.
const analytics = getAnalytics(app);

까지 코드 복사

src 내부에 service라는 폴더를 만들었다.
→ service 폴더 내부에 firebase.js를 만든다.
→ 루트 디렉토리에 .env 파일도 만든다. API key 등 github에 올라가면 안되는 정보들을 따로 저장하는 파일이다. 주의!! src폴더가 아닌 root 디렉토리에 있는지 2번 확인 3번 확인하자!!

REACT_APP_API_KEY=
REACT_APP_AUTH_DOMAIN=
REACT_APP_PROJECT_ID=
REACT_APP_STORAGE_BUCKET=
REACT_APP_MESSAGING_SENDER_ID=
REACT_APP_APP_ID=
REACT_APP_MEASUREMENT_ID=

뒤에 입력해서 env 파일에 저장하기!
여기까지는 아주 순조로워서 자신감 뿜뿜했다.
하지만.. docs 보면서 코드 작성하는 것부터는 크고 작은 난관에 부딪치는데..
쟈스민의 난관 극복 일기 시작합니다

난관 1. firebase.js에 firebaseConfig 코드 분리하기 (삽질 대장정)

이제 슬슬 코드 작성을 해볼까 룰룰루~?
처음에 나의 index.ts 파일에 코드들이 한데 모여있었다.

import React from "react";
import ReactDOM from "react-dom/client";
import { initializeApp } from "firebase/app";
import { getAnalytics } from "firebase/analytics";

import App from "./App";
import Join from "./SignUp";
import Router from "./Router";

const firebaseConfig = {
  apiKey: process.env.REACT_APP_API_KEY,
  authDomain: process.env.REACT_APP_AUTH_DOMAIN,
  projectId: process.env.REACT_APP_PROJECT_ID,
  storageBucket: process.env.REACT_APP_STORAGE_BUCKET,
  messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID,
  appId: process.env.REACT_APP_APP_ID,
  measurementId: process.env.REACT_APP_MEASUREMENT_ID,
};
initializeApp(firebaseConfig);
// const analytics = getAnalytics(app);

const root = ReactDOM.createRoot(
  document.getElementById("root") as HTMLElement
);
root.render(
  <React.StrictMode>
    <Router />
  </React.StrictMode>
);

어휴 지저분해라
firebase.ts파일을 service 폴더에 만들어서 firebaseConfig를 따로 보관하려고 했다.

초기 삽질 유발 firebase.ts파일

import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";

const firebaseConfig = {
  apiKey: process.env.REACT_APP_API_KEY,
  authDomain: process.env.REACT_APP_AUTH_DOMAIN,
  projectId: process.env.REACT_APP_PROJECT_ID,
  storageBucket: process.env.REACT_APP_STORAGE_BUCKET,
  messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID,
  appId: process.env.REACT_APP_APP_ID,
  measurementId: process.env.REACT_APP_MEASUREMENT_ID,
};

const app = initializeApp(firebaseConfig);
const auth = getAuth();
export default{ app, auth };

뭔가 이상함을 감지하셨다면 당신은..
저의 스승님이 되어주십쇼..

App.ts에서

import { auth } from "./service/firebase";

빨간 줄이 마구 그어지기 시작하는 것이었다.
에러 내용은 이러하다.

Module '"./service/firebase"'has no exported member 'auth'. Did you mean to use 'import auth from "./service/firebase"' instead?

저 firebase.ts 마지막에 export default {app, auth} 했는데염?
그렇다. 여기가 문제였다.
ㅋㅋㅋㅋㅋㅋㅋㅋㅋ

→ export default와 export의 차이 학습하여 해결

export default와 export의 차이도 모르고 쓰고 있었다.
여기가 문제였는데 여기에 빨간줄이 그어지지 않아서 몇시간 동안 몰랐다.

이번 기회에 공부해본 차이를 간략하게 정리하자면,

export default
: 해당 모듈에 한 개의 개체(클래스, 함수, 변수)만 있을 때 사용한다. 즉 export default 개체명
요런 식으로 사용.
export
: 복수의 개체가 있을 때 여러 개를 export할 수 있다.
export {개체1, 개체2}
요런 식으로 사용.

참고: https://quark21.tistory.com/314

내 코드에서 app, auth 2가지를 내보내야 하므로 export {app, auth} 이런 식으로 쓰는게 맞는 것이었다.
그래도 이번 기회에 export default와 export를 구분해서 써야 한다는 소중한 렛쓴을 얻게되었다.

firebase.ts의 마지막 줄을

export { app, auth };

이렇게 고치니 더 이상 에러가 나지 않는다.

++ 또는 어차피 app을 export할 필요가 굳이 없다면 firebase.ts 마지막 줄에

export default auth;

이렇게 auth 한개만 export default하고
App.ts에서는 import 할 때

import auth from "./service/firebase";

이렇게 중괄호를 없애고 import 해도 에러가 사라진다.
난관 1 여차저차 극복 완료!

난관2: API key undefined


https://firebase.google.com/docs/auth/web/google-signin?hl=ko&authuser=0

분명히 .env 파일에 나의 소중한 API key를 넣어놨는데 invalid-api-key라는 것이다.

const firebaseConfig = {
  apiKey: process.env.REACT_APP_API_KEY,
  authDomain: process.env.REACT_APP_AUTH_DOMAIN,
  projectId: process.env.REACT_APP_PROJECT_ID,
  storageBucket: process.env.REACT_APP_STORAGE_BUCKET,
  messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID,
  appId: process.env.REACT_APP_APP_ID,
  measurementId: process.env.REACT_APP_MEASUREMENT_ID,
};

console.log("apiKey: ", firebaseConfig.apiKey);
// apiKey: undefined

.env파일이랑 번갈아가면서 한참 헤맸다.
블로그를 돌아다녀보니 .env파일은 반드시 루트 디렉토리에 있어야 한다고 한다. 내 .env는? src폴더에 있었네? 오호호호 참 쉽군 루트 디렉토리로 이동~
하지만 여전히

console.log("apiKey: ", firebaseConfig.apiKey);
// apiKey: undefined

apiKey는 정체를 드러내지 않는 것이었다.
그렇게 삽질 무한반복한지 2시간 후..
.
.

→ vscode를 껐다 켜니까 api key를 불러올 수 있었다.


방사능 티셔츠 입고 허무함의 땐스

.env파일을 생성 후 다른 파일에서 불러오려면 vscode를 껐다 켜야만 된다고 한다.

응 오키~

난관3: docs만 읽어보고 signInWithPopup을 함수 내부에 사용해야 하는건지 한참을 모르고 헤맴.

좋았어 결심했어
나도 docs를 최우선으로 읽는 모범적인 개발자가 될테야
지금까지 docs 읽는 습관이 충분히 들여지지 못했다는 생각이 들었다.
그래서 docs를 계속 읽어봤는데.. 그랬는데..
이해가 잘 안갔다.

signInWithPopup함수를 사용하려고 하는데 기본적인 작동 원리에 대한 이해도 없이 시작해서 헤맸다.


처음에 작성을 시도했던 말도 안되는 코드

//🤣🤣🤣🤣🤣🤣
function App() {
    const auth = getAuth();
    const provider = new GoogleAuthProvider();
    signInWithPopup(auth, provider)
    .then((result) => {
      const user = result.user;
      }).catch((error) => {
      console.log(error)
      }
  };

ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ 다시 보니까 재밌다 (당시에는 진지했다구)
함수를 사용하여 코드를 묶어주고 그 함수를 login button에 onClick함수로 들어가게끔 만들어야 되는 것이었다.
그렇게 헤매다가 겨우겨우 고친 코드

.
.
(생략)
.
.
function App() {
  const [userData, setUserData] = useState(null) as any;
  const handleGoogleLogin = () => {
  // Google 제공업체 객체의 인스턴스를 생성
    const provider = new GoogleAuthProvider();
    signInWithPopup(auth, provider)
      .then((result) => {
   // user 정보를 setUserData를 이용하여 userData로 state 지정.
        setUserData(result.user);
        console.log(result);
        const name = result.user.displayName;
        console.log(name);
      })
      .catch((error) => {
        console.log(error);
      });
  };

  return (
    <BtnWrapper className='App'>
      {userData ? `${userData.displayName}님 환영합니다~` : null}
      // Btn 컴포넌트에 onClick 함수로 handleGoogleLogin 지정.
      <Btn onClick={handleGoogleLogin}>Google Login</Btn>
.
.
(생략)
.
.

→ 작동원리를 제대로 모르고 있음을 파악. 작동원리 숙지하여 해결

handleGoogleLogin이라는 함수 내부에

  • Google 제공업체 객체의 인스턴스를 생성
  • signInWithPopup함수를 실행하고 반환된 결과(result)의 user 정보를 setUserData를 이용하여 userData로 state 지정.
  • Btn 컴포넌트에 onClick 함수로 handleGoogleLogin 지정.

이렇게 헤매고 해매다보니 결국 구글 로그인 구현 성공!!

npm run build
firebase deploy

처음 들어가서 로그인하기 전

Google Login 버튼을 누르면

popup 창이 뜨고

짜잔~ 로그인 성공!!

나의 소중한 앱
https://learn-firebase-2ebf6.web.app/

firebase.ts

App.ts

여기저기 바보같은 실수를 많이 했지만 ㅋㅋㅋㅋ 난관을 헤치고 구글 로그인 구현 목표를 달성하니 아주 뿌듯하다!!
그런데

 const [userData, setUserData] = useState(null) as any;

state의 type을 설정할 때 우선 에러를 막아보려고 as any로 타입을 줬던 부분이 좀 아쉬운 것 같다.
typescript를 아직 깊게 알지 못해서 type을 어떻게 줘야할지 아직 잘 모르겠다. ㅠㅠ
typescript를 좀 더 공부해보고 나서 이부분은 꼭 다시 봐야겠다!

이제 로그아웃, 회원가입, 회원탈퇴 구현도 해봐야겠다 !
짜이찌앤~~

++멘토님도 입장 인증샷 보내주심! 뿌듯하다~~

참고:
https://firebase.google.com/docs/auth?hl=ko

https://velog.io/@jjonggang/React-%EB%A6%AC%EC%95%A1%ED%8A%B8%EC%97%90%EC%84%9C-%ED%8C%8C%EC%9D%B4%EC%96%B4%EB%B2%A0%EC%9D%B4%EC%8A%A4%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EA%B5%AC%EA%B8%80-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EA%B5%AC%ED%98%84

https://quark21.tistory.com/314

profile
기록에 진심인 개발자 🌿

0개의 댓글