문제 상황

  • 프로젝트를 진행하면서 첫 로그인 시 이용약관 동의를 받아야 하는 상황이 생겼다.
  • 학교 관련서비스로 학교 로그인 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. 첫 로그인이 아닐 때 (약관동의 후)

+ Recent posts