문제 상황

  • 프로젝트를 진행하면서 첫 로그인 시 이용약관 동의를 받아야 하는 상황이 생겼다.
  • 학교 관련서비스로 학교 로그인 api를 사용하기 때문에 학번을 id로 사용한다 . 그래서 학번을 기준으로 첫 로그인을 판단해야한다.
  • 현재 프로젝트가 백엔드리스 프로젝트로 존재했기 때문에 “어떻게 첫 로그인을 감지할까?”라는 문제상황이 있었다.

해결 방법

  • 현재 배포를 firebase를 github ci/cd와 붙여서 사용중인데, firestore를 사용해서 학번을 저장하는 방법으로 첫 로그인을 감지하자
  • firestore의 경우에는 콜렉션, 문서, 필드로 이루어진 noSql 형식의 db이다.

(첫 로그인 시)

  1. 로그인 시 firestore의 users 콜렉션을 확인하여 문서에 해당하는 학번이 존재하는지 확인한다.
  2. 존재하지 않으면 첫 로그인 이므로 약관 동의 페이지로 리다이렉션한다.
  3. 약관을 읽고 동의 버튼을 누르는 경우 firestore의 users 콜렉션에 학번을 기준으로 문서를 생성한다.

(두번 째 부터)

  1. 로그인 시 firestore의 users콜렉션에 학번이 존재하는 경우 메인페이지로 리다이렉션한다.

1. firestore생성

2. next.js 프로젝트와 연결

3. firestore의 문서 조회 및 생성으로 첫 로그인을 감지해 약관동의 페이지 리다이렉션 로직 구축

1. firebase의 firestore 추가 및 sdk 값 얻기

  • firebase에 firestore database를 해당하는 프로젝트 이름으로 추가한다.

  • 그 후 firebase에 웹앱을 추가하고 sdk값을 받는다.

2. 프로젝트에 firebase 추가

  • 프로젝트에 firebase를 추가해준다.
# npm 사용 시
npm install firebase
# yarn 사용 시
yarn add firebase

# typescript 사용 시 의존성 부여
npm install --save-dev @types/firebase
yarn add --save-dev @types/firebase
  • 위에서 얻었던 sdk값을 넣은 firebase.js(ts)파일을 루트 디렉토리에 만들어준다.
// 프로젝트 디렉토리의 root에
// firebase.js or firebase.ts
import { initializeApp } from 'firebase/app';
import { getFirestore } from 'firebase/firestore';

const firebaseConfig = {
  apiKey: '',
  authDomain: '',
  projectId: '',
  storageBucket: '',
  messagingSenderId: '',
  appId: '',
  measurementId: '',
};

const app = initializeApp(firebaseConfig);
const db = getFirestore(app);

export { db };

⇒ 이제 firestore과 연결이 완료되어서 사용할 수 있다.

3. 로그인 시 약관동의 페이지로 리다이렉션하기

  • 우선 id값을 받아, 그 id가 firestore의 users 컬렉션 내부에 존재하는 문서값인지 확인하는 함수를 작성한다.
import { doc, getDoc, setDoc } from 'firebase/firestore';
import { db } from '../../../firebase';

export const checkStudentExists = async (
  studentId: string,
): Promise<boolean> => {
  const studentRef = doc(db, 'users', studentId);
  const docSnap = await getDoc(studentRef);
  return docSnap.exists();
};
  • 그런 후 기존의 로그인 로직에서 로그인 성공 시 위에서 작성한 함수를 사용해 약관동의를 받아야할 경우 약관동의 페이지로, 그렇지 않으면 메인페이지로 라우팅을 해준다.
  const handleLogin = async (id: string, password: string) => {
    try {
        .
        .
        . // 로그인 처리하는 로직들

            // firestore의 id값이 존재하는지 확인
      const studentExists = await checkStudentExists(id);
      if (studentExists === false) {
        router.replace('/tos'); // 존재하지 않을 경우 약관동의 페이지로 이동
      } else {
        router.replace('/'); // 존재할 경우 메인페이지로 이동
      }
      return data;
    } catch (err) {

    }

약관동의 시 firestore에 새로운 문서 생성

  • irestore의 users 콜렉션 아래에 id값으로 문서 생성하는 함수 작성
import { doc, getDoc, setDoc } from 'firebase/firestore';
import { db } from '../../../firebase';

export async function createStudent(
  studentId: string,
  userData: Record<string, boolean>,
): Promise<void> {
  const studentRef = doc(db, 'users', studentId);
  try {
    await setDoc(studentRef, userData, { merge: true });
  } catch (error) {
    console.error('Error writing document: ', error);
  }
}
  • 약관동의 버튼 클릭 시 위의 함수 사용해서 문서 id값, 그리고 내부 데이터를 {”isCheckTos”:true}로 새로운 문저 생성
const handleAgree = () => {
    const user = getUserInfo();
    createStudent(user.sId, { isCheckTos: true });
    router.push('/');
  };

⇒ 이렇게 될 경우 이제 최초 로그인시에만 약관동의 페이지가 떠오르고, 약관 동의를 한 후에는 다시 로그인한다해도 바로 메인페이지로 넘어가게 된다.

결과

1. 첫 로그인 시

2. 첫 로그인이 아닐 때 (약관동의 후)

firebase 프로젝트 생성

  • firebase 생성의 경우는 해당 글 참고
 

리액트와 파이어베이스 연결하기

파이어베이스 프로젝트 생성 제일 처음 파이어베이스를 연동해주어야 함. Sign in (클릭 시 파이어베이스로 이동) 파이어 베이스 접속 후 로그인. 프로젝트 추가 클릭 프로젝트 이름 입력 애널리

enochkon.tistory.com

리액트에 firebase cli 연결

  • 배포하고 싶은 리액트 프로젝트에 firebase cli 설치
npm install -g firebase-tools
  • firebase cli에 로그인
firebase login

  • 엔터 시 로그인 창 출력
  • 연결하고 싶은 계정을 선택한 후 엑세스 동의를 해주면 cli에 로그인이 완료된다.

계정 연결 창

hosting 서비스를 이용한 배포

  • firebase init
firebase init
  • init 후 배포를 하기 위해 Hosting : Configure files…. 로 내린 후 스페이스바로 선택한 후 엔터를 누른다.

  • 아까 firebase에서 만들어놓은 프로젝트를 선택하기 위해서 “Use an existing project”에서 엔터를 누른다.

  • 처음에 만든 프로젝트를 선택해준다.

  • 배포할 디렉토리를 선택한다.
    기본값은 public, react는 빌드 시 build에 생성되므로 build를 입력해준다.

  • 그 다음은 엔터를 눌러 계속 기본값으로 넘어가다가 “Set up automatic builds and deploy with Github?” 라는 질문에서 ci/cd 구축을 위해 yes를 입력해준다.
  • 그러면 깃허브 로그인 창이 떠오르게 된다.

  • 깃허브 로그인을 성공하면 ci/cd를 연결할 user/repository를 입력한다.

  • 그 후에는 계속 엔터를 쳐주다가 What is the name of the GitHub branch associated with your site's live channel?이라는 질문에서 배포할 브랜치 이름을 적어준다.

  • 그 다음 터미널에 뜬 url을 들어가서 해당 레포의 firebase CLI를 Revoke 해준다.
i  Action required: Visit this URL to revoke authorization for the Firebase CLI GitHub OAuth App:
https://github.com/settings/**********
  • 이렇게 되면 기본적인 설정이 완료되고 .github에 yml파일이 생기고 깃허브 레포에는 github action이 추가된다.

 

이 작업까지 완료하면 수동으로 직접 배포하는 것도 가능하다

npm run build

firebase deploy

 

github action을 사용한 ci/cd 연결

  • 기본적으로 firebase와 github를 연결하게 된다면 두가지의 yml 파일이 생기게 된다.
  1. firebase-hosting-merge.yml
    • 지정한 브랜치가 병합될 때 마다 자동으로 Firebase Hosting으로 배포
# This file was auto-generated by the Firebase CLI
# https://github.com/firebase/firebase-tools

name: Deploy to Firebase Hosting on merge
'on':
  push:
    branches:
      - main
jobs:
  build_and_deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: FirebaseExtended/action-hosting-deploy@v0
        with:
          repoToken: '${{ secrets.GITHUB_TOKEN }}'
          firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_PATHTOPET }}'
          channelId: live
          projectId: pathtopet
  1. firebase-hosting-Pull-Request
    • PR을 올릴 때 Firebase Hosting에 대한 미리보기 버전을 자동으로 배포하는 것
# This file was auto-generated by the Firebase CLI
# https://github.com/firebase/firebase-tools

name: Deploy to Firebase Hosting on PR
'on': pull_request
jobs:
  build_and_preview:
    if: '${{ github.event.pull_request.head.repo.full_name == github.repository }}'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: FirebaseExtended/action-hosting-deploy@v0
        with:
          repoToken: '${{ secrets.GITHUB_TOKEN }}'
          firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_PATHTOPET }}'
          projectId: pathtopet

yml파일에 대한 간단한 내용정리

  • name: 워크플로우의 이름
  • 'on': 이 워크플로우가 어떤 GitHub 이벤트에 의해 트리거될지 정의
  • jobs: 워크플로우에서 실행할 작업을 정의
    • if: 조건문으로, 이 작업이 실행될 조건을 지정
      여기서는 pull request가 현재 저장소에서 생성된 것인지 확인.
    • ${{ github.event.pull_request.head.repo.full_name == github.repository }} 이 조건은 pull request가 포크(fork)된 저장소가 아닌 원본 저장소에서 생성됐을 때만 작업을 실행하도록 한다.
    • runs-on: 작업이 실행될 환경을 지정
    • steps: 작업을 구성하는 단계들. 이 단계들은 순차적으로 실행
      • actions/checkout@v4: GitHub Action이 현재 저장소의 코드를 체크아웃하여 작업 실행 환경에 가져온다.
      • FirebaseExtended/action-hosting-deploy@v0: Firebase Hosting으로 배포를 담당하는 GitHub Action
  • 여기서 조금 변경해서 빌드를 자동으로 한 후 그것을 배포하게 코드를 약간 바꿔준다.
name: Deploy to Firebase Hosting on merge

"on":
  push:
    branches:
      - main

jobs:
  build_and_deploy:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v2
        with:
          node-version: "21"

      - name: Install Dependencies
        run: npm install 

      - name: Build
        run: npm run build 
        env:
          CI: false

      - uses: FirebaseExtended/action-hosting-deploy@v0
        with:
          repoToken: "${{ secrets.GITHUB_TOKEN }}"
          firebaseServiceAccount: "${{ secrets.FIREBASE_SERVICE_ACCOUNT_PATHTOPET }}"
          channelId: live
          projectId: pathtopet
name: Deploy to Firebase Hosting on PR

"on": pull_request

jobs:
  build_and_preview:
    if: "${{ github.event.pull_request.head.repo.full_name == github.repository }}"
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v2
        with:
          node-version: "21" 

      - name: Install Dependencies
        run: npm install 

      - name: Build
        run: npm run build 
        env:
          CI: false

      - uses: FirebaseExtended/action-hosting-deploy@v0
        with:
          repoToken: "${{ secrets.GITHUB_TOKEN }}"
          firebaseServiceAccount: "${{ secrets.FIREBASE_SERVICE_ACCOUNT_PATHTOPET }}"
          projectId: pathtopet
  • 배포되기전 빌드를 자동으로 해주기 위해 node js를 사용해서 npm install 후 build 해준다.

 

이렇게 되면 잘 배포되는것을 확인할 수 있다.

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

제일 처음 파이어베이스를 연동해주어야 함.

Sign in (클릭 시 파이어베이스로 이동)

  • 파이어 베이스 접속 후 로그인.
  • 프로젝트 추가 클릭
  • 프로젝트 이름 입력
  • 애널리틱스 건들지 않고 넘어가기
  • 기존의 계정 혹은 새 계정 만들고 선택 후 프로젝트 생성

firebase 프로젝트에 웹앱 추가

  • 앱 추가 클릭 후 웹 클릭
  • 이름 입력 후 다음 클릭
![](https://velog.velcdn.com/images/fdsa200/post/d0fab8aa-6c0b-4f51-9021-2b00dd0c3506/image.png)
  • sdk 설정에 있는 js 코드 복사

리엑트에 파이어베이스 추가

위에서 웹을 추가할 때 봤던 sdk설정에 있는 내용에 리엑트에 추가

  • 파이어 베이스 설치
npm install firebase
  • 설치 후 firebase.js 파일 하나 만들어서 위의 내용 복사&붙여넣기 (파일이름은 상관없음)

+ Recent posts