[토이 프로젝트] 장미전쟁 score tracker 만들기: Firebase 호스팅, 구글 로그인 및 인증 지속 구현

이민선(Jasmine)·2023년 5월 30일
1
post-thumbnail

이번 포스팅에는 Firebase로 google 로그인을 구현한 과정을 담으려고 한다.

FireBase 호스팅

일단 Firebase로 빠르게 호스팅부터 하고 올게욥~

과거 Firebase 호스팅 배웠던 기록을 참고했다.
https://velog.io/@jasmine0714/firebase-hosting%EC%9D%84-%EB%B0%B0%EC%9B%8C%EB%B3%B4%EC%9E%90

베리 나이스 신속하게 호스팅 완료!

드디어 이 프로젝트에도 도메인이 생겼어!!

Google Login 구현 과정

이제 진짜 google login을 시작해보자.



구글 사용 설정 완료!

- firebaseConfig 저장

.env파일에 firebaseConfig의 value들을 저장 후, src 내부에 service 폴더 생성. 그리고 service 폴더 내부에 firebase.ts 파일 생성 후 아래와 같이 작성하였다.

firebaseConfig 저장 완료!
app과 auth export도 완료!

근데 나 지난 번 포스팅 참고하면서 하고 있는데, 왜 firebaseui에 대한 언급은 없지??
firebase는 애플리케이션의 백엔드 인프라를 제공하는 플랫폼이라면,
firebaseui는 인증 관련 기능에 특화된 라이브러리이다.
firebaseui를 사용하면 Firebase의 인증 기능을 사용할 수 있게 되는 것이쥐!
그래서 바로 설치~

npm install firebaseui --save


이제 본격적으로 Firebase SDK를 사용하여 Google 로그인 구현을 시작해보자. 아까부터 시작한 것 같지만 이제부터가 진짜 시작임.

- handleGoogleLogin 함수 생성

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

일단 docs와 최대한 비슷하게 코드를 짜야 덜 헷 갈릴 것 같아서 getAuth 함수 호출하는 코드를 로그인 버튼이 있는 Home 컴포넌트로 옮겨주었다.

그래서 이렇게 handleGoogleLogin 함수를 docs를 보고 짜보았는데..
로그인 버튼을 누르니까 에러가 나네?

- 😈 Error : No Firebase App has been created - call initializeApp first

//... import 생략
import { getAuth, signInWithPopup, GoogleAuthProvider } from "firebase/auth";

function Home() {
    const [userName, setUserName] = useState<string | null>(null);
    const handleGoogleLogin = () => {
    const provider = new GoogleAuthProvider();
    // 이 부분이 에러의 원인 😈
    const auth = getAuth();
    signInWithPopup(auth, provider)
    .then((result) => {
      // This gives you a Google Access Token. You can use it to access the Google API.
      const credential = GoogleAuthProvider.credentialFromResult(result);
      const token = credential?.accessToken;
      // The signed-in user info.
      const user = result.user;
      console.log(user);
    })
    .catch((error) => {
      console.log(error.message);
    });
};

  return (
    <>
      <GameTitleContainer>
        <GameTitle>The War of Rose</GameTitle>
        <GameTitle>: Score Tracker</GameTitle>
      </GameTitleContainer>
      <GoogleLoginContainer onClick={handleGoogleLogin}>
        <GoogleLogoBtn></GoogleLogoBtn>
        <GoogleLoginBtn>Google Login</GoogleLoginBtn>
      </GoogleLoginContainer>
    </>
  );
}
export default Home;

handleGoogleLogin함수를 생성해서 GoogleLoginContainer에 onClick으로 연결해주었다. signInWithPopup함수에 auth와 provider 객체를 인자로 넘기면 GoogleAPI에 접근할 수 있도록 access token을 받아올 수가 있다. 그리고 result의 user 속성을 console 출력하면 내 기억으로 로그인 하는 사람의 이름이 출력되었었는데..!

no-app이요?.. 나 분명 firebase.ts에서 initializeApp함수 import 해와서

export const app = initializeApp(firebaseConfig);

이렇게 app 생성했는데 왜 no-app이지??

이럴 때일 수록 docs에 충실해서 살펴보자.

- error 원인 파악/해결: app을 getAuth 함수에 인자로 전달

초기화가 잘못된 것 같아서

다시 보니 내 코드에서 getAuth를 호출할 때 app을 인자로 전달하지 않았었다.

const auth = getAuth(app);

그래서 firebase 파일에서 app을 import해와서 getAuth함수에 인자로 전달했다.

// app을 import 해와서
import app from "../../service/firebase";
import { getAuth, signInWithPopup, GoogleAuthProvider } from "firebase/auth";

function Home() {
  const [userName, setUserName] = useState<string | null>(null);
  
  const handleGoogleLogin = () => {
    const provider = new GoogleAuthProvider();
    // getAuth에 app을 인자로 넘겨주면서 getAuth를 호출해야 한다.
    const auth = getAuth(app);
 .
 .
 (생략)

다시 구글 로그인 버튼 클릭! 두근두근

와우!!!!!!!!
로그인 팝업창 떴다~~~
나는 console 출력해달라고 했기 때문에 auth관련 정보들이 console 창에 뜨는데,

이렇게 access token과 refresh token, 그리고 만료되는 시간도 보인다. 와웅 다시 해봐도 너무 재밌어~~!!!!!!

- 인증 지속 구현 (session storage에 인증 지속을 위한 정보 저장)

근데 과거 포스팅에서도 다뤘던 것처럼 인증 상태를 지속 시키려면 추가적으로 구현을 해야 한다.

[firebase] authentication② 로그인 인증 상태 지속, useHistory, 로그아웃 구현
https://velog.io/@jasmine0714/firebase-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EC%9D%B8%EC%A6%9D-%EC%83%81%ED%83%9C-%EC%A7%80%EC%86%8D

지금은 in-memory 방식이기 때문에 새로고침하면 로그인이 풀려버리쥬?

나는 유저가 브라우저 창을 끄기까지는 새로고침을 하더라도 로그인 상태를 유지시키려고 한다.
지난번과 같이 setPersistence와 browserSessionPersistence를 사용해서 SESSION 방식을 구현하는 것이다. 참고로 LOCAL 방식을 구현하려면 browserLocalPersistence를 사용하면 된다. 나는 웹 스토리지의 보안적 취약점이라는 한계를 생각해보면, 적어도 창을 껐을 때 세션에 있는 token 등 중요 정보는 날아가도록 하는 쪽이 낫겠다고 판단해서 LOCAL 방식이 아닌 SESSION 방식을 택했다.

export declare interface Persistence {
    /**
     * Type of Persistence.
     * - 'SESSION' is used for temporary persistence such as `sessionStorage`.
     * - 'LOCAL' is used for long term persistence such as `localStorage` or `IndexedDB`.
     * - 'NONE' is used for in-memory, or no persistence.
     */
    readonly type: 'SESSION' | 'LOCAL' | 'NONE';
}


세션 스토리지에 token이 저장되고, 새로고침을 해도 정보가 날아가지 않는다.

- my page 리디렉션 시 새롭게 직면한 문제

이제 handleGoogleLogin 함수의 생성은 완료가 되었으니 마이페이지로 리디렉션 해보려고 한다.

  • MyPage 컴포넌트를 생성하고 Route로 MyPage의 path를 /mypage로 설정해주었다.
  • handleGoogleLogin 함수 내부에 useNavigate을 사용해서 navigate("/mypage")를 추가해주었다.

로그인하면 이제 마이페이지로 잘 넘어가긴 하는데.. 문제가 2가지가 있다.

[🧐 미해결 상태]

  • 로그인을 하지 않은 상태에서 url에 직접 /mypage path를 입력하고 엔터를 누르면 mypage로 이동한다. 즉 로그인하지 않은 유저의 마이페이지 접근을 제한하는 것이 불가능함.
  • 로그인하고 마이페이지에 왔을 때 "누구누구님" 하고 이름을 띄워주는데, useState에 상태를 저장하다보니 마이페이지에서 유저가 새로고침하면 더 이상 이름이 뜨지 않음.

이 2가지 문제를 해결해보자.
다음 포스팅에서 다루도록 하겠다. 씨유쑨!

profile
기록에 진심인 개발자 🌿

0개의 댓글