[React + Firebase] Firestore를 이용해 회원가입 구현하기

Hadam Cho·2022년 11월 21일
0

Project

목록 보기
3/4
post-thumbnail

이 글은 Firebase Authentication에 저장할 수 없는 추가 정보를 Firestore에 저장하여 회원가입 하는 방법에 대해 다룹니다.

만약 Firebase Authentication을 통한 사용자 생성을 아직 구현하지 않으셨다면,
[React + Firebase] 카카오 로그인 구현하기 (1)
[React + Firebase] 카카오 로그인 구현하기 (2)
윗글을 먼저 보시는 것을 추천해 드립니다.

Cloud Functions for Firebase

지난 글에서는 커스텀 토큰만 클라이언트로 전송해 로그인을 구현한 뒤 마쳤습니다. 생성한 유저 ID를 이용해 회원가입을 진행하기 위해 작성한 코드를 수정해야 합니다.

저는 카카오 로그인을 통해 받아온 유저 정보를 활용하기 위해 ID 외에도 몇 가지 추가 정보를 클라이언트로 전송하였습니다.

아래 코드를 참고하여 functions/src/index.ts를 수정합니다.

app.post("/kakao", async (req, res) => {
  ...
  const kakaoUser = await getKakaoUser(token);
  
  const authUser = await updateOrCreateUser(normalizedUser);
  const firebaseToken = await admin
  	.auth()
  	.createCustomToken(authUser.uid, { provider: "KAKAO" });

  return res.status(200).json({
    kakaoUser: {
      ...kakaoUser,
      id: authUser.uid
    },
    firebaseToken,
  });
});

코드를 수정했으므로 다시 배포를 진행합니다.

yarn deploy

React

firestore에 저장된 유저가 있는지 확인해야 하므로, config.ts를 수정합니다.

import { getFirestore } from "firebase/firestore";
...
export const auth = getAuth(app);
export const db = getFirestore(app);

Firestore 인스턴스를 export 해준 뒤, 콜백 페이지를 수정해 주어야 합니다.
아래 코드를 참고하여 상황에 맞게 인증 및 사용자 확인을 해 주시면 되고, 코드에 대한 설명은 주석으로 달아두겠습니다.

import { doc, getDoc } from "firebase/firestore";
import { auth as firebaseAuth, db } from "../config";
...

const KakaoLogin = () => {
  const [isLoading, setIsLoading] = useState(true);
  const [auth, setAuth] = useState<Auth | null>(null);
  ...
  
  useEffect(() => {
    (async () => {
      try {
        const res: AxiosResponse<Auth> = await axios.post(
          "/api/auth/kakao", 
          { code }
        );
        const {
          kakaoUser: { id },
          firebaseToken,
        } = res.data;

        // Firebase Auth 사용자 id를 이용해
        // Firestore에서 동일한 유저 문서를 가져옴
        const user = await getDoc(doc(db, "users", id));

        if (user.exists()) {
          // Firestore에 저장되어 있다면 회원가입이 되어있다는 뜻이므로
          // 커스텀 토큰을 이용해 로그인 처리
          await signInWithCustomToken(firebaseAuth, firebaseToken);
        } else {
          setAuth(res.data);
        }

        setIsLoading(false);
      } catch (error) {}
    })();
  }, []);

  if (isLoading) {
    return <Loading.Full />;
  }

  return (
    <Layout>
      {auth ? (
        // 유저 문서가 없었다면 회원가입 페이지로 이동
        <Navigate to="/signup" state={auth} />
      ) : (
        <Navigate to="/" replace />
      )}
    </Layout>
  );
};

회원가입 페이지의 경우 원하는 대로 구현해 주시면 됩니다.

이후 입력받은 유저 정보를 바탕으로 컬렉션에 유저 문서를 추가하면 회원가입이 완료됩니다. 아래는 예시 코드입니다.

import { signInWithCustomToken } from "firebase/auth";
import { doc, setDoc } from "firebase/firestore";
import { auth, db } from "../config";
import { useLocation } from "react-router-dom";

const SignUp = () => {
  // Navigate 컴포넌트를 통해 전달한 state
  const { state } = useLocation();
  
  const onSubmit = async () => {
    const user = convertStateToUser(state);
	await setDoc(doc(db, "users", state.kakaoUser.id), user);
    await signInWithCustomToken(auth, state.firebaseToken);
  };
  
  return (
    <button onClick={onSubmit}>회원가입</button>
  );
};

정리

❶ API 응답에 유저 ID를 포함한다.
❷ 받아온 유저 ID를 통해 Firestore에 해당 유저 문서가 있는지 확인한다. (회원가입 여부)
❸ 유저가 있다면 받아온 커스텀 토큰을 통해 로그인한다.
❹ 유저가 없다면 회원가입 페이지로 이동해 추가 정보를 입력받는다.
❺ 추가 정보를 가지고 유저 문서를 추가해준 뒤 커스텀 토큰을 통해 로그인한다.


이번 글은 Firestore에 있는 데이터를 읽고 저장하는 방법에 대해 다뤄보았습니다. 부족한 부분은 댓글로 알려주시면 개선하도록 하겠습니다!

다음 글에서는 React Context를 이용하여 로그인된 경우에만 홈 화면에 접근할 수 있도록 처리하는 방법에 대해 작성해 보겠습니다.


참고

profile
(。・∀・)ノ゙

0개의 댓글