react로 twitter만들기(1)

dooga·2024년 4월 14일
0

프로젝트

목록 보기
3/5

Firebase Authentication

  • 쉽게 사용자 인증을 구현할 수 있도록 돕는 Firebase 서비스
  • 이메일과 비밀번호 인증, 소셜 미디어 인증, 전화번호 인증
  • 인증 정보 안전하게 저장(보안이 강화되어 있음)
  • 인증 정보 변경시 실시간으로 앱에 업데이트
  • 인증 이메일 전송, 비밀번호 재설정 이메일 전송 등의 기능

로컬 회원가입

  1. Firebase 프로젝트 생성, Firebase SDK 앱 추가
  2. Firebase 초기화
  3. Firebase Authentication 함수로 사용자 인증

소셜 로그인(Google OAuth)

  1. Google 제공업체 객체의 인스턴스를 생성
  2. Google 제공업체 객체를 사용해 Firebase에 인증(signInWithPopup)

Firebase Authentication 시작하기

  • firebase console에 들어가 프로젝트 생성
  • SDK발급을 위해 프로젝트를 선택 후 웹 선택
  • 앱 이름을 입력
  • SDK 발급
  • firebaseApp.ts 파일에 설정
import { initializeApp, FirebaseApp, getApp } from "firebase/app";

export let app:FirebaseApp;
// 이렇게 하는 이유는 initialize를 호출할때마다 매번 하지 않고 try,catch를 이용해 initialize가 되어있으면 getApp을 통해서 해당 앱을 가져오고, 아니라면 initialize를 하기 위함

const firebaseConfig = {
  apiKey: process.env.REACT_APP_API_KEY,
  authDomain: process.env.REACT_APP_AUTH_DOMAIN,
  projectId: process.env.REACT_APP_PROJECT_ID,
  storageBucket: process.env.REACT_APP_STORAGE_BUCKET,
  messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID,
  appId: process.env.REACT_APP_APP_ID,
};

// Initialize Firebase
try {
  app = getApp("app");
} catch (e) {
  app = initializeApp(firebaseConfig, "app");
}

const firebase = initializeApp(firebaseConfig);

export default firebase;
  • 최상단 컴포넌트에서 getAuth를 이용해서 currentUser가 있는지 없는지 판별
import { getAuth } from "firebase/auth";
import { app } from "firebaseApp";

function App() {
  const auth = getAuth(app);
  return (
    <Layout>
      <Router />
    </Layout>
  );
}

createUserWithEmailAndPassword(회원가입)

  • 공식문서
  • 해당 프로젝트의 Authentication에 들어간 후 로그인 방법 탭에서 이메일/비밀번호 선택
const onSubmit = async (e: any) => {
    e.preventDefault();

    try {
      const auth = getAuth(app);
      await createUserWithEmailAndPassword(auth, email, password);
      navigate("/");
      toast.success("성공적으로 회원가입이 되었습니다.");
    } catch (error: any) {
      toast.error(error?.code);
    }
  };
  • 이러면 회원가입은 되지만 사용자를 인식하지 못하기에 새로고침을 해줘야하는 이슈가 있다.
  • 이때 사용하는 것이 onAuthStateChanged메서드이다. 공식문서
// app.tsx
import Router from "pages/components/Router";
import { Layout } from "pages/components/Layout";
import { getAuth, onAuthStateChanged } from "firebase/auth";
import { app } from "firebaseApp";
import { useState, useEffect } from "react";
import { ToastContainer } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";

function App() {
  const auth = getAuth(app);

  const [isAuthenticated, setIsAuthenticated] = useState<boolean>(
    !!auth?.currentUser
  ); // currentUser 초기값은 null이라 true,false로 로그인 상태인지 로그아웃 상태인지 판별하기 위함

  const [init, setInit] = useState<boolean>(false); 
  // auth를 의존성 배열에 넣고 onAuthStateChanged가 되면 init의 값을 true로 변경. 

  useEffect(() => {
    onAuthStateChanged(auth, (user) => {
      if (user) {
        setIsAuthenticated(true);
      } else {
        setIsAuthenticated(false);
      }
      setInit(true);
    });
  }, [auth]);

  return (
    <Layout>
      <ToastContainer />
    // init의 값에 따라 Router를 보여줄지 loading 스피너를 보여줄지 분기처리
      {init ? (
        <>
          <Router isAuthenticated={isAuthenticated} />
        </>
      ) : (
        "loading"
      )}
    </Layout>
  );
}

export default App;

signInWithEmailAndPassword(로그인)

  • 회원가입과 똑같고 signInWithEmailAndPassword만 바꾸면 된다.
const onSubmit = async (e: any) => {
    e.preventDefault();

    try {
      const auth = getAuth(app);
      await signInWithEmailAndPassword(auth, email, password);
      navigate("/");
      toast.success("성공적으로 회원가입이 되었습니다.");
    } catch (error: any) {
      toast.error(error?.code);
    }
  };

signOut(로그아웃)

const clickLogout = async () => {
 const auth = getAuth(app);
 await signOut(auth);
 toast.success("로그아웃 되었습니다.");
}

OAuth란?

  • OAuth(Open Authorization) : 사용자가 다른 애플리케이션 혹은 서비스의 리소스에 접근할 수 있도록 허용하는 프로토콜
  • OAuth1.0 : 서명된 요청을 통해 사용자 인증 처리. 하지만 복잡하고 사용이 어려움
  • OAuth2.0(SNS 로그인)
    • 간결한 방식으로 사용자 인증.
    • 클라이언트와 리소스 소유자 사이의 권한 부여 관리.
    • 토큰 기반의 접근 방식 사용.

OAuth 구성요소

  • 주요 원리 : 사용자의 계정 정보를 안전하게 다른 서비스의 리소스에 접근할 수 있게 하는 것
  • Resource Owner : 보호된 리소스에 대한 액세스 권한을 가진 사용자 (ex : 사용자의 Google 계정은 리소스 오너)
  • Client : 리소스에 접근하려는 애플리케이션/서비스
  • Authorization Server : 사용자의 인증을 처리하고 클라이언트에게 액세스 토큰 제공
  • Resource Server : 실제로 보호된 리소스를 호스팅하고 있는 서버

OAuth 인증과정

  1. client -> resource owner (리소스 접근 권한 요청)
  2. resource owner -> authorization server (요청 승인 & 권한 부여)
  3. authorization server -> client ( Access Token 발급)
  4. client -> resource server (Access Token 저장)
  5. resource server -> client (토큰 검증 & 요청 처리)

OAuth 장단점

  • 사용자가 자신의 계정 정보를 외부 애플리케이션에 노출하지 않아도 됨
  • 보안성 및 사용자 경험 향상(간편한 로그인/회원가입)
  • 서비스 간에 사용자 정보 공유X. 각 서비스별 독립성 유지
  • 하지만, OAuth를 직접 구현하고 관리하는 것은 복잡하고, 보안 이슈가 생길수도 있음
    • Firebase의 Authentication은 복잡한 OAuth를 편리하게 구현할 수 있도록 도와줌

Firebase OAuth 적용

  • Authentication에 들어간 후 새 제공업체 추가
  • 공식문서
//소셜로그인 부분
const onClickSocialLogin = async (e: any) => {
    const {
      target: { name },
    } = e;

    let provider;
    const auth = getAuth(app);

    if (name === "google") {
      provider = new GoogleAuthProvider();
    }

    if (name === "github") {
      provider = new GithubAuthProvider();
    }

    await signInWithPopup(
      auth,
      provider as GithubAuthProvider | GoogleAuthProvider
    )
      .then((result) => {
        console.log(result);
        toast.success("로그인 되었습니다.");
      })
      .catch((e) => {
        console.log(e);
        const errorMessage = e?.message;
        toast.error(errorMessage);
      });
  };

0개의 댓글