firebase를 사용하며 맞닥드린 문제와 해결법

·2024년 1월 14일

study

목록 보기
5/7
post-thumbnail

서론

최근 진행한 프로젝트에서 firebase를 활용하였다.
나는 이 프로젝트에서 firebase를 처음 사용하게 되었고,
진행하면서 겪은 수 많은 시행착오들에 대하여 기록을 남기려고 한다.

문제와 해결

1. 구글 로그인시 Cross-Origin-Opener-Policy 오류

문제

가장 처음 맞닥드린 문제는 구글 로그인 부분이었다. 관련 가이드는 아래 링크와 같다.
firebase-인증-웹-Firebase SDK로 로그인 과정 처리

구글 로그인을 하는 방식에는
1. 팝업
2. 리다이렉트
두 가지 방법이 있었다. 나는 프로젝트에 팝업 방식을 적용하였다.

해당 기능을 적용하고 로그인 시도를 했을 때, 계정이 없다면 신규 가입, 있다면 로그인을 해 준다.
가입 및 로그인 기능 자체는 잘 되었는데, 문제는 콘솔창에 뜨는 오류였다.

해당 문제는 로그인이 되어있는 상태에서 로그인을 시도하면 생기는 문제라고 하는데...
로그아웃을 하고 onAuthStateChanged 에서도 user 정보가 보이지 않는데도 뜬다.
검색을 하면서 발견한 해결 방법이 몇 가지가 있는데... 약간의 편법들이 들어간 방법이라, 궁극적인 해결 방법은 찾지 못하였다.

제시된 해결 방법 (해결 못함)

  1. 팝업 자체의 문제, signInWithPopup -> signInWithRedirect로 변경
    해당 부분은 적용을 했지만, 제대로 작동이 안되며 프로젝트의 로그인 페이지로 다시 리다이렉트 시키고 있어 패스하였다.
  2. HTTPS 연결이 없어서 발생
    https 연결이 있는 배포된 사이트에서 진행해보았는데, 여전히 동일한 오류가 발생했다.
  3. 서드 파티 쿠키 활성화
    로컬 및 배포 사이트 URI를 모두 추가하고 시도 했는데, 여전히 동일한 오류가 발생했다.
  4. 메타 태그 추가
    index.html에 <meta name="Cross-Origin-Opener-Policy" content="same-origin">를 추가하였지만, 여전히 동일한 오류가 발생했다.

내가 찾은 모든 해결방법을 적용해보았지만 결국 해결하지 못하였다.
일단 기능은 잘 되어 넘어가고 이후에 수시로 확인해보았지만, 여태 해결을 하지 못했다.
혹시 해결 방법을 아시는 분이 있다면 알려주시면 감사합니다.

2. 로그인 유저 정보 확인

문제

CSR 방식으로 개발되었기 때문에, 새로고침을 할 때 마다 로그인 정보가 날아가는 문제가 있었다. 해당 문제를 해결하고자 처음에는 localStorage에 로그인 token을 저장하는 방법을 사용하려 했다. token을 localStorage에 저장하고 받아오는 것 까지는 가능했으나, 서버가 따로 존재하지 않았기에 클라이언트에서는 token으로 유저 정보를 받아올 수 있는 방법이 없었다.

해결 방법

생각보다 간단한 방법으로 해결되었다. firebase에서 제공하는 onAuthStateChanged 메서드를 사용하면 로그인 유저를 받아올 수 있었다.
나는 다음과 같이 onAuthStateChanged를 사용하여 유저가 존재한다면 uid를 가지고 서버에서 user 정보를 받아오도록 로직을 구성하였다.

const initUser = () => {
  this.auth.onAuthStateChanged(user => {
    if (user) {
      login(user.uid);
    }
  });
};

사실 이 메서드의 존재는 처음부터 알고 있었으나, 활용법을 제대로 몰라 한참을 헤맸던 것 같다.
나름 공식문서를 꼼꼼히 읽었다고 생각했는데, 다음엔 좀 더 제대로 읽어야겠다. 😅

3. 이미지 URL 생성

문제

이미지 업로드 기능을 구현하던 중, 이미지를 URL로 받아올 수 있는 방법이 없을까 싶어 찾아보았다. 처음에는 firebase 내에 기능이 없는 줄 알고 Base64 형식으로 보냈지만, 데이터의 크기가 커서 url로 변경하는 방법을 다시 찾았다.

해결 방법

방법은 간단했는데, firebase console에서 storage 기능을 활성화 시켜주면 된다.

  • firebase 설정 파일에 getStorage 메서드로 storage를 받아온다.
  • Rules 부분에 인증 사용자만 사용할 수 있도록 규칙을 추가해준다.
    allow read, write: if request.auth != null;
  • uploadBytes 메서드를 사용하여 원하는 위치에 원하는 파일이름으로 업로드를 하면 된다.
  • getDownloadURL 메서드를 사용하여 업로드한 파일의 URL을 받아온다.

적용한 코드는 아래와 같다.
하나의 이미지만 올리고, 파일 이름은 "현재timestamp_랜덤숫자" 형태로 올리도록 하였다.

const handleUpload = (event: Event) => {
  const target = event.target as HTMLInputElement;
  const file: File = (target.files as FileList)[0];
  if (!file) return;

  // 파일 이름을 고유하게 만듭니다.
  const fileName = Date.now() + "_" + Math.floor(Math.random()*10000);
  // Firebase Storage에 저장할 파일 경로를 지정합니다.
  // images 폴더 아래에 이미지가 저장됩니다.
  const filePath = `images/${fileName}`;

  // 업로드할 파일의 다운로드 URL을 생성합니다.
  uploadBytes(ref(storage, filePath), file)
  .then(() => {
    // 업로드한 이미지 URL을 받아옵니다.
    getDownloadURL(ref(storage, filePath))
    .then((url) => {
      imageUrl.value = url;
    });
  })
  .catch(e => {
    console.log(`이미지 업로드에 실패했습니다. ${e}`);
  });
};

그 외 어려움이 있었던 부분들

  1. 게시글 문자열 검색, 게시글 기간 검색 구현 불가

마무리

간단한 프로젝트를 구성할 때는 서버를 굳이 구축하지 않고 간편하게 사용할 수 있는 장점이 있지만, 조금만 복잡한 로직을 구현하려 하면 기능적 문제가 있어 쉽지 않았다.
특히 조건이 많은 조회성 SQL문을 작성하는 데 큰 무리가 있어서 원하는 기능을 구현하지 못하기도 했다.
firebase를 다시 사용할거냐 라고 물어봤을 때, 개인적으로는 부정적 입장이다.
차라리 내가 서버를 직접 구축하는게 더 편한 것 같다는 생각을 많이 했기 때문이다.
결국 해당 프로젝트는 서버를 별도로 개발하기로 결정하였다.

하지만, 부피가 작은 프로젝트를 진행한다면, firebase는 좋은 선택권 중 하나가 될 것이다.
빠르게 프로토타입을 보여야 할 때는 firebase를 사용하는 것이 좋은 것 같다.

profile
개발 공부를 하고, 작업을 합니다.

0개의 댓글