문제 상황
- 프로젝트를 진행하면서 첫 로그인 시 이용약관 동의를 받아야 하는 상황이 생겼다.
- 학교 관련서비스로 학교 로그인 api를 사용하기 때문에 학번을 id로 사용한다 . 그래서 학번을 기준으로 첫 로그인을 판단해야한다.
- 현재 프로젝트가 백엔드리스 프로젝트로 존재했기 때문에 “어떻게 첫 로그인을 감지할까?”라는 문제상황이 있었다.
해결 방법
- 현재 배포를 firebase를 github ci/cd와 붙여서 사용중인데, firestore를 사용해서 학번을 저장하는 방법으로 첫 로그인을 감지하자
- firestore의 경우에는 콜렉션, 문서, 필드로 이루어진 noSql 형식의 db이다.
(첫 로그인 시)
- 로그인 시 firestore의 users 콜렉션을 확인하여 문서에 해당하는 학번이 존재하는지 확인한다.
- 존재하지 않으면 첫 로그인 이므로 약관 동의 페이지로 리다이렉션한다.
- 약관을 읽고 동의 버튼을 누르는 경우 firestore의 users 콜렉션에 학번을 기준으로 문서를 생성한다.
(두번 째 부터)
- 로그인 시 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. 첫 로그인이 아닐 때 (약관동의 후)