VueJS/Vite

[VueJS] Firebase 구글 로그인(Vite, Vue3, TS)

SongMinu 2023. 1. 24. 14:46
728x90

 

1. 파이어베이스 프로젝트 생성

https://console.firebase.google.com/u/0/?hl=ko 

 

로그인 - Google 계정

이메일 또는 휴대전화

accounts.google.com

여기에 접속해서 사용할 프로젝트를 추가한다.

프로젝트 이름은 본인이 원하는 이름으로...
구글 애널리틱스는 활성화해도 상관 없지만 여기선 해제

여기까지 다 되면 사용준비는 거의 다 끝이다.

2. 파이어베이스 프로젝트 설정

위 생성이 끝나면 메인화면에 아래와 같이 5개의 아이콘이 있다.

우선 웹만 사용할거라 아이콘 5개 중 3번째 아이콘 웹을 선택한다.

앱 닉네임을 입력한다.

난 그냥 프로젝트와 동일한 이름으로 입력했고, 호스팅 설정은 체크하지 않았다.

앱 등록 버튼을 클릭하면 아래와 같이 출력된다.

npm과 script로 사용할 때 사용할 수 있는 방법을 알려준다.

여기선 npm으로 사용해서 만들 예정이라 firebaseConfig 정보를 따로 저장해 주자.

프로젝트 생성이 완료되면 나중에 프로젝트 설정 화면에서 다시 확인할 수 있다.

이제 콘솔로 이동 버튼을 클릭

버튼을 누르면 화면이 이동된다.

왼쪽 사이드 메뉴에서 빌드를 누르고 [Authentication] 메뉴로 이동한다.

인증에 사용할 수 있는 것들...

사용할 수 있는 종류가 많은데 여기선 구글 로그인만 할 예정이라 구글을 클릭한다.

처음 접속하면 사용 설정이 비활성화 되어 있는데 활성화시키면 프로젝트의 공개용 이름이 활성화된다.

이후 프로젝트 지원 이메일을 클릭해서 본인의 이메일을 선택하면 저장 버튼이 활성화된다.

저장을 누르면 준비가 완료된다.

 

3. Vite 프로젝트 작업

Vite 프로젝트 생성

npm create vite@latest

cd 본인이 만든 프로젝트명
npm i
npm run dev

프로젝트 생성 시 vue와 typescript를 선택

파이어베이스 모듈 설치

npm i firebase

.env 세팅

위에서 받았던 파이어베이스 설정 값은 공개되면 안 되기 때문에 .env를 만들어서 설정 값을 입력해 준다.

vite에서 .env를 사용하기 위해선 VITE_를 붙여줘야 해서 난 VITE_FB_ 형식으로 만들어줬다.

vite가 업데이트돼서 그런 건지 모르겠는데 env를 사용하기 위해선 vite.config.js에서 loadEnv를 import 해서 별도의 작업이 필요했었는데 지금은 필요 없어진 것 같다. 
이 프로젝트 생성 당시 버전은 4.0.0이다.

alias 세팅

작업할 때 디렉터리 접근을 편하게 하기 위해 별칭 설정을 먼저 했다.

vite.config.ts를 열어 보면 아래와 같이 작성되어 있을 것이다.

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
});

이걸 아래와 같이 수정한다.

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import { resolve } from 'path';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: [
      {
        find: '@',
        replacement: resolve(__dirname, 'src'),
      },
    ],
  },
});

그리고 tsconfig.json도 열어서 수정을 해줘야 한다.

compilerOptions 안에 baseUrl과 paths 옵션을 추가한다.

"baseUrl": ".",
"paths": {
  "@/*": ["./src/*"]
}

파이어베이스 작업할 디렉터리 생성

웹 외부와 통신하는 작업 디렉터리로 src 및에 apis 디렉터리를 생성 후 위와 같이 파일을 구성했다.

index.ts는 export를 담당해 주고, initApp.ts은 초기화, GoogleAuth.ts에는 구글 로그인과 관련된 로직을 담을 예정이다.

인증 초기화

initApp.ts 파일을 열어서 작성

import { initializeApp } from 'firebase/app';

const {
  VITE_FB_apiKey,
  VITE_FB_authDomain,
  VITE_FB_databaseURL,
  VITE_FB_projectId,
  VITE_FB_storageBucket,
  VITE_FB_messagingSenderId,
  VITE_FB_appId,
  VITE_FB_measurementId,
} = import.meta.env;

const firebaseConfig = {
  apiKey: VITE_FB_apiKey,
  authDomain: VITE_FB_authDomain,
  databaseURL: VITE_FB_databaseURL,
  projectId: VITE_FB_projectId,
  storageBucket: VITE_FB_storageBucket,
  messagingSenderId: VITE_FB_messagingSenderId,
  appId: VITE_FB_appId,
  measurementId: VITE_FB_measurementId,
};

export const app = initializeApp(firebaseConfig);

initApp.ts와 같은 위치에 있는 index.ts에도 소스 작성

export { app } from './initApp';

구글 로그인 로직 작성

GoogleAuth.ts 파일을 열어서 작성

import {
  Auth,
  getAuth,
  GoogleAuthProvider,
  signInWithPopup,
  signOut,
  User,
} from 'firebase/auth';
import { app } from '.';

export class GoogleAuthAPI {
  private auth: Auth;
  private provider: GoogleAuthProvider;
  constructor() {
    this.auth = getAuth(app);
    this.provider = new GoogleAuthProvider();
  }

  //현재 로그인 중인 유저 정보
  get nowUser(): User | null {
    return this.auth.currentUser;
  }

  //로그인
  signIn(): Promise<User> {
    return new Promise(async (resolve, reject) => {
      try {
        const { user } = await signInWithPopup(this.auth, this.provider);
        resolve(user);
      } catch (err) {
        reject(err);
      }
    });
  }

  //로그아웃
  signOut(): void {
    signOut(this.auth);
  }
}

auth는 파이어베이스 인증 초기화

관련 공식문서 링크(https://firebase.google.com/docs/auth/web/start?hl=ko&authuser=0)

provider는 구글 공급자 개체에 대한 인스턴스를 만들어준다.

관련 공식문서 링크(https://firebase.google.com/docs/auth/web/google-signin?hl=ko&authuser=0)

 

공식문서에는 타입스크립트에 대한 설명이 없어서 만들면서 힘들기도 했던 부분이기도 하다.

공식문서에 나와있는 소스를 입력하고, import 한 객체를 타고 들어가서 어떤 타입을 사용하는지 직업 확인하면서 적용했다.

class 방식으로 작성한 이유?
이건 좀 개인적인 취향이긴 한데 웹 외부와 통신하는 부분을 작업할 때 apis라는 디텍터리를 만들고, 그 안에 추가적으로 디렉터리 이름으로 구분 짓고 작업하는 파일들은 class 기반의 객체지향 방식으로 작성하는 것을 선호한다.
추적하기 쉽게 하기 위해 디렉터리와 파일 이름에서 어디 기능, 어떤 기능인지 의미를 간략하게 담아두고, 작성한 코드가 어떤 기능인지 하나의 객체로 담아서 사용하는 게 좋다고 생각이 들어서 이런 방식으로 작업하게 되었다.

그리고 로그인에서 signInWithPopup은 로그인 시 팝업창을 이용해 로그인을 할 수 있는 기능을 제공해 준다.

다른 방법도 제공해 주니 https://firebase.google.com/docs/auth/web/google-signin?hl=ko&authuser=0 여기서 확인해 보면 된다.

 

위 소스를 작성 후 같은 위치에 있는 index.ts에 export를 해준다.

export { app } from './initApp';
export { GoogleAuthAPI } from './GoogleAuth';

그리고 apis 디렉터리 안에 있는 index.ts를 열어서 GoogleAuthAPI만 export 해준다.

export { GoogleAuthAPI } from './firebase';

이렇게 하는 이유는 다른 파일에서 apis를 사용할 때 import { ~ } from '@/apis'만 입력해서 GoogleAuthAPI만 import 할 수 있게 하기 위해 이렇게 작성했다. (필요한 것만 접근시키기 위해)

로그인 기능 구현

간단하게 확인을 하기 위해 App.vue 파일에서만 작업.

script 단에 아래와 같이 작성한다.

<script setup lang="ts">
import HelloWorld from './components/HelloWorld.vue';
import { User } from 'firebase/auth';
import { GoogleAuthAPI } from '@/apis'
const googleAuth = new GoogleAuthAPI();

//로그인
const signIn = async (): Promise<void> => {
 try {
    const user: User = await googleAuth.signIn();
    console.log(user);
  } catch (err) {
    console.error(err);
  }
}
</script>

그리고 template 단에 로그인 기능을 실행할 버튼을 추가한다.

<button @click="signIn">로그인</button>

 

화면 및 기능

로그인 버튼을 누르면 팝업이 출력된다.

그리고 위에 작성된 로그인 로직에서 console.log를 확인해 보면 

로그인한 구글 계정의 정보를 확인할 수 있다.

열어보면 고유아이디인 uid 그리고 이메일주소, 이름, 프로필 이미지 주소, 토큰 등 각종 정보들이 담겨있다.

여기서부턴 이제 각자 본인의 방식으로 로그인을 유지하는 로직을 만들면 된다.

 

이 이후에 작업은 작성하지 않을 생각인데 이유는 나도 아직 정확히 어떻게 처리하는 게 좋은지 잘 모르겠다.

로그인 유지에 관련해서도 공식문서에 정보가 있는데 

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

 

인증 상태 지속성  |  Firebase

Google은 흑인 공동체를 위한 인종적 평등을 추구하기 위해 노력하고 있습니다. 자세히 알아보기 이 페이지는 Cloud Translation API를 통해 번역되었습니다. Switch to English 의견 보내기 인증 상태 지속

firebase.google.com

여기에 보면 우선 기본적으로 브라우저를 닫아도 로그인 정보가 브라우저에 계속 남는 게 기본 값이다.

그래서 로그인 시도 후 브라우저를 닫았다 다시 켜서 GoogleAuth.ts에 있는 nowUser를 실행시켜 보면 값이 나온다.

값을 바꾸고 닫으면 로그아웃 되는 방법도 있고 그렇다.

구글링 해보니 토큰 값 같은걸 로컬스토리지에 넣어두고 로컬스토리지에 있으면 로그인을 유지하는 방법을 사용하는 사람들도 많은 것 같다.

 

개인 플젝은 기본 값을 이용해 만들긴 했는데

한 가지 문제가 로그인해둔 상태에서 웹을 새로고침 하면 유저 정보를 가져오는 약간의 텀이 있어서 로그인 버튼이 보였다가 로그아웃 버튼이 활성화되는 현상이 눈에 보인다.

아직 이걸 어떻게 처리해야 할지 좋은 아이디어가 없어서 방치해 둔 상태로 다른 작업들을 하고 있다.

로컬스토리지를 쓰면 될 것 같긴 한데 이 방법 말고 다른 방법으로 해결해보고 싶어서 공식문서를 좀 더 뒤져보려고 하긴 했는데 시간이 좀 많이 필요해 보여서 우선 다른 작업들을 처리하기 위해 보류 중이다.

 

작업한 소스

https://github.com/smw0807/minu_vuejs/tree/master/firebase-login-typescript

 

GitHub - smw0807/minu_vuejs: Vue.js study

Vue.js study. Contribute to smw0807/minu_vuejs development by creating an account on GitHub.

github.com

 

여기선 간략하게 보여주기 위해 App.vue에서 apis에 다이렉트로 처리하게 했는데

개인 플젝에서는 api 처리는 pinia를 통해 처리하게 했다.

https://github.com/smw0807/pubg_your.stat

 

GitHub - smw0807/pubg_your.stat: 배그 스탯 검색 사이트

배그 스탯 검색 사이트. Contribute to smw0807/pubg_your.stat development by creating an account on GitHub.

github.com

 

 

반응형