[Firebase] 유저 인증 및 Realtime DB 인증 규칙으로 유저 검증하기

한음·2022년 8월 22일
1
post-thumbnail

주말간의 삽질

상황

  • 파이어베이스 리얼타임 DB 를 이용하려고 함 (웹)
  • 테스트 모드로 하기 싫었고 인증 규칙을 사용하려 했는데 죄다 write&read 권한을 풀어놓은 자료들만 있음
  • 공식문서가 너무 파편화되어 유저 가입 -> 인증 -> 작성 플로우를 따라가기가 힘들어 헤맴

결론적으로 공식문서를 똑바로 안읽었었다 ㄱ- 미안아 구글해

그래도 상황에 적은 것처럼 파이어베이스 서비스 이용에 있어 인증부터 사용까지 전체적인 플로우 가이드가 많이 없다.

그래서 써봉다

Vue 기반으로 진행했는데 리액트로 해도 동일하다.


해결

절차

진행하려는 절차는 아래와 같다.

  1. 유저 등록
  2. 유저 로그인
  3. DB 접근 요청시 Validation 후 요청 처리

1. 유저 등록

파이어베이스는 다양한 유저 인증 방법을 제공한다. 나는 검증 메일을 선택했고, 다른 방법을 택하더라도 흐름은 동일하다.

절차는 아래와 같다.

입력한 유저 이메일로 인증 메일 전송
-> 메일 내 링크로 이동 (서비스 내 로그인 처리 라우트)
-> *이동하며 받아온 인증 토큰을 담아서 sign in 요청 전송
-> 인증 완료 후 서비스 메인으로 redirect

** 당연히 firebase app 설정 및 실행은 서비스 내에서 완료된 상태여야 한다.

firebase.js

import {
  getAuth,
  sendSignInLinkToEmail,
  isSignInWithEmailLink,
  signInWithEmailLink,
} from "firebase/auth";

const auth = getAuth();
const actionCodeSettings = {
  url: process.env.VUE_APP_SIGN_IN_ROUTE_DEV,
  // 메일 내 링크로 접속했을때 이동할 URL 을 설정한다.
  // 로그인 요청을 위한 별도의 라우트를 만들어준다. (${BASE_URL}/login/validate 이런식으로)
  // 해당 페이지에서 인증이 끝나면 main 으로 redirect 한다.
  handleCodeInApp: true,
};

2. 유저 로그인

// 인증 메일 발송.
// localStorage 에 email 을 저장해서 메일 링크로 접속 시 메일을 요청한 user 가 맞는지 이중 검증한다.
export const sendSignInLink = (email) => {
  sendSignInLinkToEmail(auth, email, actionCodeSettings)
    .then(() => {
      localStorage.setItem("signInEMail", email);
    })
    .catch((error) => {
      console.log(error);
    });
};


// 메일을 통해 인증 라우트로 들어왔으면, 인증 요청을 보낸다.
// url 쿼리에 인증 토큰이 담겨있어 현재 주소를 인자로 보낸다.
export const signInFirebase = async () => {
  const email = localStorage.getItem("signInEMail");
  if (!email) return false;
  localStorage.clear();

  if (isSignInWithEmailLink(auth, window.location.href)) {
    const response = await signInWithEmailLink(
      auth,
      email,
      window.location.href
    );
    return response;
  }
};
SignIn.vue

<template>
  <div>Check Login ...</div>
</template>

<script>
import { signInFirebase } from "@/firebase";
export default {

  // mount 시 로그인 요청을 보내고, 응답이 오면 userId, uid 를 localStorage 에 저장한다.
  // 새로고침시 Vuex 가 초기화되어 서비스 내 로그인 상태가 해제되는걸 막아준다. 
  // Vuex 의 로그인 상태로 true 로 처리해준다.
  mounted() {
    signInFirebase().then((response) => {
      const userId = response.user.auth.currentUser.email;
      const uid = response.user.uid;
      localStorage.setItem("userId", userId);
      localStorage.setItem("uid", uid);
      this.toastMessage("Success to Sign In :)", "success");
      this.$store.dispatch("signIn", { userId, uid });
      this.$router.push("/");
    });
  },
  inject: ["toastMessage"],
};
</script>
App.vue

...
// 새로고침시 localStorage 에 저장된 정보가 있다면 Vuex 로그인 상태를 업데이트한다.
mounted() {
    if (localStorage.getItem("userId")) {
      const userId = localStorage.getItem("userId");
      const uid = localStorage.getItem("uid");
      this.$store.dispatch("signIn", { userId, uid });
    }

여기까지 오면 firebase app 내 auth 정보가 들어간다.
**SDK 이용해 처리하면 app 내에서 sign-in 상태기 때문에 알아서 인증을 처리해주는데

Realtime DB 규칙 플레이그라운드 예제 보면서 Axios 로 헤더 설정해 날리려고 하니까 세부 설정을 다 맞추지 못해서 주말내내 사방팔방을 들쑤시고 다녔다.

SDK 를 이용하자

임시로 설정한 규칙. 로그인 후 SDK 이용한 요청은 auth 객체를 이용할 수 있으니 필요한 대로 설계해 사용하면 된다.


realtimeDB.js

import { getDatabase, ref, set } from "firebase/database";

export const database = getDatabase(app);

export const writeDB = (DBLocation, obj) => {
  /*
  * database: firebase database 앱
  * DBLocation: 저장할 NoSQL 경로 쿼리 (문자열)
  * obj: 저장할 key - value
  */
  set(ref(database, DBLocation), obj);
};

로그인까지 다 해놓고 저거 이용 못해서 주말 날린게 화낙만두

profile
https://github.com/0hhanum

0개의 댓글