[React, Firebase] Firebase Auth를 이용한 로그인/회원가입 기능 구현

이은지·2023년 11월 28일
0

Firebase Authentication, Firestore 기능을 이용해 로그인, 회원가입 기능을 구현할 것이다.

1. 파이어베이스 세팅

🌻 Firebase 인증 초기화

  • getAuth 모듈을 import해 Firebase 인증을 초기화

🌻 Firebase 로그인 방법 설정

  1. Firebase 콘솔에서 해당 프로젝트에 접속
  2. 제품 카테고리의 빌드> Authentication>시작하기>User탭 클릭
  3. 로그인 방법 설정(Sign-in-method)버튼 클릭
  4. ‘이메일/비밀번호’와 ‘Google’선택
  5. 사용 설정을 해주고 저장 클릭
  • 설정 완료

🌻 FireStore

  • Firebase에 포함되어 있는 서비스 중 하나로 유연하고 확장 가능한 NoSQL 클라우드 데이터베이스
  • 구조
    • Collection: 문서(document)의 집합
    • Document: JSON 형식으로 데이터를 저장

🌻 Firestore 세팅 방법

  1. Firebase Console > Firestore에서 '데이터베이스 만들기' 버튼 클릭
  2. 프로덕션 모드 선택
  3. Firestore 데이터베이스 물리적 위치 선택 (본인은 가장 가까운 asia-northeast3로 지정)
  4. 규칙 수정 > 임시로 테스트 할때는 read, write를 모두 할 수 있도록 설정
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if true;
    }
  }
}

🌻 User 컬렉션 정보 구성하기

  • users(collection)
    • Uid(document)
      • Email (field)
      • Nickname (field)
      • Uid (field)
      • UserName (field)

2. 로그인/회원가입 기능 구현

🔆 파일 구성

  • 페이지
    • SignInPage.jsx : 로그인 페이지를 렌더링하고, 사용자의 로그인 로직을 처리
    • SignUpPage.jsx : 회원가입 페이지를 렌더링하고, 사용자의 회원가입 로직을 처리
    • Signupinstyle.js: styled-component 스타일 속성을 모아둔 파일
  • 리덕스 파일
    • user.js: 하나의 파일에 user와 관련된 Action Type, Action Creator, Reducer가 모두 담겨져 있는 모듈 파일
  • 파이어베이스 파일
    • firebase_user.js: firestore와 연동하여 유저 관련 데이터를 처리하는 함수를 모아둔 파일

🔆 로그인 - SignInPage

  • 구글 소셜 로그인 또는 이메일, 비밀번호를 통한 로그인이 가능함
  • 계정이 없을 경우, Sign up 버튼을 클릭하면, 회원가입 페이지로 이동
  • handleGoogleSignIn 함수
    • Firebase SDK를 사용하여 Google 로그인 과정을 진행
const handleGoogleSignIn = async (e) =>{
      e.preventDefault();
      const provider = new GoogleAuthProvider(); //Google 제공업체 객체의 인스턴스 생성 
      const auth = getAuth(); //Firebase authentication 객체 생성 

      try{
        const data = await signInWithPopup(auth, provider); 
		//팝업창을 이용하여 로그인 과정 진행 (비동기 작업)
        const uid = data.user.uid; //로그인 시 사용자의 uid 필요 

        const response = await dispatch(signInUser(uid)) 
		//Redux 액션을 사용하여 사용자의 로그인 정보를 redux 스토어에서 관리하는데 사용  
				
		//액션의 응답을 확인하여 사용자가 이미 회원가입한 경우와 아직 회원가입하지 않은 경우를 구분
        if(response.payload === false){
          alert('회원가입을 진행해주세요')
          navigate('/signup')
        }else{
          navigate('/');
        }
      }
      catch(error){
        console.log(error);
      }
  }
  • handleEmailSignIn 함수
    • Firebase 인증을 사용해서 사용자가 이메일 계정과 비밀번호로 로그인 과정을 진행
const handleEmailSignIn = async (e) => {
    e.preventDefault();
    const auth = getAuth();
    try{  
      const data = await signInWithEmailAndPassword(auth, Email, Password)
	//이메일과 비밀번호로 로그인, 로그인한 사용자 세부 정보를 반환해줌 
        
      const uid = data.user.uid;
      const response = await dispatch(signInUser(uid)) //signInUser라는 액션에 uid를 넣어줌 
      if(response.payload === false){
        alert('회원가입을 진행해주세요')
        navigate('/signup')
      }else{
        navigate('/');
      }
    }catch(error){
      console.log(error);
    }
  }

🔆 회원가입 - SignupPage

  • 구글 소셜 회원가입 또는 이메일,비밀번호를 통한 회원가입이 가능함
  • 계정이 있을경우, Login! 클릭 시 로그인 페이지로 이동
  • handleGoogleSignUp 함수
    • firebase authentication을 이용해 구글 계정 로그인 시 로그인한 사용자의 정보를 가져오고, 만약 사용자의 uid가 firestore 에 없을 경우, 회원가입 폼 렌더링 (Visible state를 통해 조건부 렌더링)
    • 이미 firestore에 uid가 있을 경우, 로그인 페이지 이동
const handleGoogleSignUp = async (e) =>{
    e.preventDefault();
    const provider = new GoogleAuthProvider(); //Google 제공업체 객체의 인스턴스 생성 
    const auth = getAuth();

    try{
      const data = await signInWithPopup(auth, provider); //팝업창을 이용하여 로그인 과정 진행 (비동기 작업)
      console.log(data);
      const uid = data.user.uid; //로그인 시 사용자의 id 필요 
      console.log("uid : ",uid);

      const response = await findUser(uid)
      console.log(response);
      if(response.payload === false){
        setUserName(data.user.displayName);
        setEmail(data.user.email);
        setUid(data.user.uid);

        setVisible(!Visible);

      }else{
        alert('이미 회원가입 되어 있는 상태입니다. 로그인 하세요')
        navigate('/signin')
      }
    }
    catch(error){
      console.log(error);
    }
  • handleEmailSignUp 함수
    • firebase authentication을 이용해 사용자가 입력한 이메일과 비밀번호로 새로운 사용자 계정을 생성하는데, 성공적으로 생성되면 회원가입 폼을 렌더링
    • 만약 사용자의 계정이 이미 존재할 경우("auth/email-already-in-use" 오류 발생) 다른 이메일 계정을 통해 가입할 것을 경고창에 뜨게함
const handleEmailSignUp = (e) => {
  e.preventDefault();
  const auth = getAuth();

  createUserWithEmailAndPassword(auth, Email, Password)
  .then((userCredential)=>{
    //Signed in 
    const user = userCredential.user;
    console.log(user);
    setEmail(user.email);
    setUid(user.uid);

    // 계정 생성 성공한 후 RegisterForm 컴포넌트를 렌더링
    setVisible(!Visible);     
	})
  .catch((error)=>{
      // 오류 처리
      const errorCode = error.code;

      if(errorCode === "auth/email-already-in-use"){
        alert("이미 사용중인 이메일 주소입니다. 다른 이메일 주소를 사용하세요")
      }else{
        console.log(error);
      }
  })
  • 회원가입 폼
    • 이메일, 이름, 닉네임을 입력 받음. 이메일의 경우 사용자가 가입 진행한 이메일 정보가 default로 입력되어 있음
    • 사용자가 정보를 입력하고 Submit 버튼을 클릭하면, onSubmit 버튼이 실행
const onSubmit = async(e)=>{
  e.preventDefault();
  let variable = {
    Uid: Uid,
    UserName: UserName,
    Email: Email,
    Nickname: Nickname,

  }
  try{
    const response = await dispatch(signUpUser(variable))
		 
    if(response.payload === "success"){ //회원가입이 성공적으로 이루어진 경우, 사용자를 홈 페이지로 리디렉션
      navigate('/')
    }
  }catch(error){
    throw error;
  }

}
  • onSubmit 함수

    • 사용자가 입력한 정보를 variable에 저장
    • Redux 액션을 사용하여 사용자를 회원으로 등록. signUpUser 액션은 사용자 정보를 Firebase 또는 서버에 저장하고 회원가입 프로세스를 처리하는 데 사용

🔆 Redux-User.js

  • Redux를 사용하여 user와 관련된 Action Type, Action Creator, Reducer를 정의한 모듈 파일
  1. Action 유형을 정의한 상수
//Actions
const SIGN_IN = 'user_reducer/signin';
const SIGN_UP = 'user_reducer/signup'
  1. 액션 생성자
  • signInUser: 사용자 uid를 입력으로 받아서 findUser함수를 호출하여, 사용자를 찾고, 결과를 액션 페이로드로 반환함
  • signUpUser: 사용자 데이터를 저장하고, 결과를 액션 페이로드로 반환
// Action Creators
export function signInUser(uid){
    
    const result = findUser(uid);

    return { 
        type: SIGN_IN, //type: 액션의 유형
        payload: result //payload: 액션과 함께 전달되는 데이터 포함

    };

};

export async function signUpUser(userdata){

    const result = await saveUser(userdata);
    console.log(result);

    return{
        type: SIGN_UP,
        payload: result
    }

  
}
  1. 리듀서
  • 리듀서는 SIGN_INSIGN_UP 액션을 처리
  • 이러한 액션들에 대한 상태 업데이트를 수행하며, loginSuccessregister 필드를 업데이트하여 사용자의 로그인 및 회원가입 상태를 관리
//Reducer
export default function (state = {}, action){
    switch (action.type) {
        case SIGN_IN:
            return {...state, loginSuccess: action.payload} //state를 똑같이 가져오고, user_actions의 payload를 넣어줌 
        case SIGN_UP:
            return {...state, register: action.payload}
        default:
            return state;
    }
}

🔆 파이어베이스 - firebase_user.js

  • Firebase Firestore를 사용하여 사용자 관련 데이터를 처리
  • findUser 함수
    • findUser 함수는 사용자 UID를 기반으로 Firestore에서 사용자를 검색
    • const users = firestore.collection("users");를 사용하여 "users" 컬렉션에 대한 참조를 얻음
    • await users.where("Uid", "==", uid).get();를 사용하여 Uid 필드가 주어진 UID와 일치하는 문서들을 검색
    • snapshot.size를 사용하여 검색된 결과의 문서 수를 확인하고, 결과가 1개 이상인 경우에는 true를 반환하고, 그렇지 않으면 false를 반환
    • 오류 처리를 위해 try-catch 블록을 사용
  • saveUser 함수:
    • saveUser 함수는 사용자 데이터를 Firestore에 저장
    • await users.doc(userdata.Uid).set(userdata);를 사용하여 주어진 UID를 가진 문서에 사용자 데이터를 저장
    • 데이터 저장이 성공하면 "success" 문자열을 반환
    • 오류 처리를 위해 try-catch 블록을 사용
profile
소통하는 개발자가 꿈입니다!

0개의 댓글