(Firebase) User and Token management

Mirrer·2023년 2월 13일
0

Firebase

목록 보기
2/2
post-thumbnail

Firebase User management

데이터베이스를 직접 관리하는 방법 대신, Firebase 의 계정 관리 API를 사용하여 유저의 정보를 관리하는 Algorithm 순서는 다음과 같다.


App Config

계정 관리 API를 사용하기 전 Firebase 홈페이지에서 발급받은 각종 인증키를 연결한다.

또한 인증 키는 보안을 위해 .env 파일로 관리한다.

import { initializeApp } from 'firebase/app';
import { getAuth } from 'firebase/auth';

// app config 정보 등록
const firebaseConfig = {  
  apiKey: process.env.NEXT_PUBLIC_FIREBASE_APIKEY,
  authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTHDOMAIN,
  projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
  storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
  messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
  appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
  measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID,
};

// Initialize Firebase
export const fbApp = initializeApp(firebaseConfig);
export const fbAuth = getAuth(fbApp);

Sign In

FirebasecreateUserWithEmailAndPassword _API를 사용하면 회원가입 기능_을 쉽게 구현할 수 있다.

또한 updateProfile API는 가입된 회원에 정보를 추가 한다.

위 과정을 통해 정상적으로 가입이 완료된 회원은 Firebase에 고유 uid 생성된다.

import { signup } from '@actions/user';

const SignupForm = () => {
  const [email, onChangeEmail] = useInput('');
  const [password, onChangePassword] = useInput('');

  const onSubmitForm = useCallback(() => {   
      // 회원가입 액션 실행
      dispatch(signup({ email: email, password: password }));      
  }, []);

  return (
    <>
      <form onSubmit={onSubmitForm}>                    
        <input type="text" id="email" name="email" value={email} onChange={onChangeEmail} />
        <input type="text" id="email" name="email" value={password} onChange={onChangePassword} />         
      </form>
    </>
  );
};

export default SignupForm;
import { createAsyncThunk } from '@reduxjs/toolkit';
import { fbAuth } from '@pages/api/auth/fBase';
import { createUserWithEmailAndPassword, updateProfile } from 'firebase/auth';

export const signup = createAsyncThunk('user/signup', async (data, { rejectWithValue }) => {
  try {
      // 입력받은 유저의 이메일, 패스워드를 통해 회원가입
      const credential = await createUserWithEmailAndPassword(fbAuth, data.email, data.password);
      // 회원가입이 완료된 유저의 닉네임을 추가
      await updateProfile(fbAuth.currentUser, { displayName: data.nickname });      
    }   
  } catch (error) {    
    return rejectWithValue(error.response.data);
  }
});

Login

Firebase signInWithEmailAndPassword API를 사용하면 로그인 기능 또한 쉽게 구현할 수 있다.

정상적으로 로그인이 완료된 사용자는 Firebase 에 저장된 고유 uid 와 매칭되는 인증 토큰이 생성된다.

import { login } from '@actions/user';

const LoginForm = () => {
  const [email, onChangeEmail] = useInput('');
  const [password, onChangePassword] = useInput('');

  const onSubmitForm = useCallback(() => {   
      // 로그인 액션 실행
      dispatch(login({ email: email, password: password }));      
  }, []);

  return (
    <>
      <form onSubmit={onSubmitForm}>                    
        <input type="text" id="email" name="email" value={email} onChange={onChangeEmail} />
        <input type="text" id="email" name="email" value={password} onChange={onChangePassword} />         
      </form>
    </>
  );
};

export default LoginForm;
import { createAsyncThunk } from '@reduxjs/toolkit';
import { fbAuth } from '@pages/api/auth/fBase';
import { signInWithEmailAndPassword } from 'firebase/auth';

export const signup = createAsyncThunk('user/signup', async (data, { rejectWithValue }) => {
  try {
      // 입력받은 유저의 이메일, 패스워드를 통해 로그인
      const credential = await signInWithEmailAndPassword(fbAuth, data.email, data.password);      
  } catch (error) {    
    return rejectWithValue(error.response.data);
  }
});

Authentication Token

로그인시 발급된 인증 토큰은 접속한 유저를 식별하며, 추후 사용을 위해 Session, Local Storage...등 별도의 저장소에 저장한다.

import { createAsyncThunk } from '@reduxjs/toolkit';
import { fbAuth } from '@pages/api/auth/fBase';
import { signInWithEmailAndPassword } from 'firebase/auth';

export const signup = createAsyncThunk('user/signup', async (data, { rejectWithValue }) => {
  try {    
    const credential = await signInWithEmailAndPassword(fbAuth, data.email, data.password);
    // 접속한 유저의 토큰
    const token = await credential.user.getIdToken();
    setToken(token);
  } catch (error) {    
    return rejectWithValue(error.response.data);
  }
});
const setToken = token => {
  // 전달받은 토큰을 local Storage에 저장
  localStorage.setItem('FB_TOKEN', token);
};

API request

API 요청시 저장된 토큰을 요청 헤더에 추가한다.

단, 인증 토큰에는 유효 기간이 있어 onIdTokenChanged API를 통해 만료 여부를 확인한 뒤 만료된 토큰은 새롭게 교체하여 요청을 수행한다.

axios.interceptors.request.use(
  async config => {
    const token = await getToken(); // 로컬 스토리지에 저장된 토큰 가져오기
    config.headers.Authorization = `Bearer ${token}`; // 요청 헤더에 토큰을 추가
    return config;
  },
  error => {
    return Promise.reject(error);
  },
);
export const getToken = () => {
  fbAuth.onIdTokenChanged(async user => { // 토큰이 만료되었다면
    if (user) {
      // 새로운 토큰을 로컬스토리지에 저장
      const newToken = await user.getIdToken();
      setToken(newToken); 
    }
  });

  const token = localStorage.getItem('FB_TOKEN') ?? '';
  return token;
};

Logout

로그아웃은 FirebasesignOut API로 구현할 수 있으며, Local Storage에 저장된 토큰 또한 함께 삭제한다.

export const logout = createAsyncThunk('user/logout', async () => {
  try {
    await fbAuth.signOut(); // 사용자 로그아웃
    localStorage.removeItem('FB_TOKEN'); // 로컬 스토리지의 토큰도 함께 삭제
  } catch (error) {
    console.log(error);    
  }
});

Social Login

FirebaseGoogle, Facebook...등등 많은 소셜 네트워크 서비스의 로그인 연동 기능을 지원한다.

기본 적인 사용방법은 일반 사용자 로그인과 동일하며, 서비스에 맞는 별도의 공급자를 생성하여 계정 정보를 추가한다.

import { createAsyncThunk } from '@reduxjs/toolkit';
import { fbAuth } from '@pages/api/auth/fBase';
import { GoogleAuthProvider, signInWithPopup } from 'firebase/auth';

export const signup = createAsyncThunk('user/signup', async (data, { rejectWithValue }) => {
  try {    
    // 구글 계정 공급자 생성
    const provider = new GoogleAuthProvider();
    // 팝업창을 이용하여 구글 계정 로그인 연동
    credential = await signInWithPopup(fbAuth, provider);

    // 접속한 유저의 토큰을 Local Storage에 저장
    const token = await credential.user.getIdToken();
    setToken(token);
  } catch (error) {    
    return rejectWithValue(error.response.data);
  }
});


참고 자료

커스텀 인증 시스템을 사용하여 Firebase에 인증

profile
memories Of A front-end web developer

0개의 댓글