인트로


시간이 참 빠르게 흘러 이제 다음 주면 마무리 주가 될 것 같습니다. 빠르게 프로젝트를 완성하고 싶지만, 아직 완성 단계는 아닙니다. 이번 주는 막판 스퍼트를 위해 힘을 내야 할 것입니다. 이번 주에는 heroku 환경 변수로 firebase admin key를 숨기는 것과 react 프로젝트를 로컬에서 빌드하고 충돌을 해결해 보았습니다. 그리고 장소에 좋아요를 누르는 API 기능도 만들었습니다.

heroku 환경 변수를 사용하여 Firebase Admin Key 파일 깃허브에서 숨기기


Firebase 키를 처음부터 깃허브에서 숨기고 싶었지만 방법을 찾던 도중 오늘 드디어 해결하였습니다. 방법은 heroku 환경 변수를 사용하여 프로젝트가 헤로쿠에서 빌드 될때 firebase admin key 값이 포함된 json 파일을 만들도록 하는 것입니다.
방법을 순차적으로 설명하겠습니다.

  1. 우선 heroku에서 본인의 프로젝트에 들어갑니다.
  2. 우측 상단에 Settings로 들어갑니다.
  3. Reveal Config Vars라는 버튼이 존재하는데 해당 버튼을 클릭하여서 firebase admin key 값을 json 파일 통째로 넣어줍니다.

해당 과정이 끝났다면 거의 다 진행 되었습니다.
이번엔 Procfile을 수정합니다.

web sh -c 'echo ${FIREBASE_ADMIN_KEY} >> ./firebase.json && java -Dserver.port=$PORT $JAVA_OPTS -Dspring.profiles.active=prod-jar build/libs/heroku-sample-0.0.1-SNAPSHOT.jar'

여기서 간단하게 Procfile에 대해 설명해보자면, Procfile은 heroku를 빌드한 다음 실행과정이 들어가 있는 파일입니다.
ProcFile은 web 이라는 단어로 시작되어야 합니다. 여기서 sh -c를 사용하면 bash 명령어를 삽입할 수 있습니다. 여기서 sh -c 의 역할은 ''안에 명령어를 하나로 묶는 역할을 합니다.
echo ${FIREBASE_ADMIN_KEY} >> ./firebase.json 명령어는 헤로쿠에서 설정한 FIREBASE_ADMIN_KEY를 ./firebase.json파일에 저장한다는 의미입니다.

React 프로젝트 로컬에서 빌드하기


React 프로젝트를 로컬에서 빌드하기 위해서는 node.js를 설치해야됩니다. npm도 설치 해야되지만 node.js를 설치하면 자동으로 설치가 됩니다.

node -v, npm -v로 잘 깔렸는지 확인함과 동시에 버전을 체크할 수 있습니다.

  cd frontend
  npm install
  npm run build
  cd ..
  mkdir src/main/resources/static/
  cp -r frontend/build/* src/main/resources/static/

npm run build 명령어로 프론트엔드 프로젝트를 빌드하여 빌드 파일을 생성할 수 있습니다.

만났던 오류들


로그 관련 오류

 error: cannot find symbol

        log.info("test log");

        ^

  symbol:   variable log

테스트 코드를 작성하면서 로그를 사용하니 위와같은 오류를 만났습니다. 해당 오류를 해결하기 위해서 build.gradle 파일에

testAnnotationProcessor 'org.projectlombok:lombok'

해당 코드를 작성하면 됩니다.
만약 테스트 환경이아니라 로컬 환경에서 해당 오류를 만났다면

annotationProcessor 'org.projectlombok:lombok'

위 코드를 추가해주시면 됩니다.

@BeforeAll 관련 오류


@BeforeAll 어노테이션을 실험삼아 실행해보니 오류가 발생했습니다.

BeforeAll() throws java.lang.Exception' must be static

해당 오류의 내용은 BeforeAll이라는 메소드가 반드시 static으로 선언되어있어야 한다는 의미입니다. 해당 내용을 적용하여 아래와 같이 static을 붙이면 문제가 해결 됩니다.

    @BeforeAll
    public static void BeforeEach() throws Exception {
        log.info(" 통과 ");
    }

@ResponseBody를 사용하지 않아서 발생한 오류


클라이언트에게 요청을 받고 요청을 보낼 때 @ResponseBody를 사용하지 않으니 자바 객체의 Long 타입에 관련한 에러가 발생하였습니다. 이를 해결 하기 위해서는 @ResponseBody 어노테이션이 필요한데 어노테이션의 역할은 자바 객체를 http 응답 body의 객체로 변환하여 클라이언트로 전송합니다. @ResponseBody 어노테이션을 자주 사용한다면 @RestController 어노테이션을 활용하면 좋은 방법이 될 수 있습니다. @RestController는 별도로 어노테이션을 설정 해주지 않아도 리턴 값에 @ResponseBody 어노테이션이 붙게 됩니다.

파이어 베이스 로그인 오류


이번 주에 드디어 프론트엔드와 백엔드 프로젝트를 통합해서 해로쿠에 배포 해보았습니다. 하지만 로그인 연동에서 많은 삽질을 하게 되었지만 해결 돼서 정말 기쁜 것 같습니다.
우선 처음 만났던 오류는 프론트 엔드에서 넘겨주는 값에 bearer가 포함되어 있지 않아서 발생한 에러였습니다.
jwtFilter에서 request의 헤더 부분의 Athorization 값에는 bearer가 포함되어서 해당 부분이 있는지 체크하게되는데 없어서 Invalid token 에러를 발생하여 이를 프론트엔드 부분에서 수정하였습니다.
그 다음도 에러를 만났는데 이번에는 토큰이 잘못되어 있었습니다.
오류는 다음과 같습니다.

com.google.firebase.auth.FirebaseAuthException: Firebase ID token has incorrect "aud" (audience) claim. Expected "for-rest-7f9d8" but got "652669951852-qpk8g3597toibf3mnnlhqoakij2evup6.apps.googleusercontent.com". Make sure the ID token comes from the same Firebase project as the service account used to authenticate this SDK. See https://firebase.google.com/docs/auth/admin/verify-id-tokens for details on how to retrieve an ID token.

해당 오류를 발견하고 백엔드 프로젝트와 프론트엔드 프로젝트는 같은 파이어베이스 프로젝트에서 생성한 Key값을 사용해야한다는 것을 깨달았습니다.
하지만 그래도 오류가 해결 되지 않았습니다. 여기서 부터 이제 잘 해결되지 않아 멘토님의 도움을 받았습니다.
해당 문제의 원인은 프론트엔드에서 Google의 Credential을 직접 사용해서 발생한 것이었습니다. 따라서, firebase 유저 객체에서 getIdToken을 통해 토큰을 가져오도록 하여 문제를 해결 하였습니다.

좋아요 누르기 동작 방식

좋아요를 누르게 되면 get 방식으로 placeId 값을 pathVariable로 받게됩니다. 그리고 서비스로 유저 정보와 placeId를 넘깁니다. 그러면 서비스에서는 좋아요를 이미 눌렀는지 안눌렀는지 확인합니다.

 // 좋아요를 이미 누른 상태인지 확인
        Optional<Love> result = loveRepository.findByMemberAndPlace(member,place);

좋아요를 이미 눌렀다면 Place의 likeCount를 1 마이너스하고 love 테이블에서 좋아요를 눌렀던 정보를 제거합니다. 반대로 좋아요를 누른 정보가 없다면 likeCount값을 1 증가 시키고 love 테이블에 특정 장소에 내가 좋아요를 눌렀다는 정보를 저장합니다.

        // 좋아요를 처음 누른 경우
        if(!result.isPresent())
        {
            Love love = Love.builder()
                    .member(member)
                    .place(place)
                    .build();

            // 좋아요를 증가 시킴
            PlaceRepository.plusLikeCount(PlaceId);
            return loveRepository.save(love).getId();
        }
        // 좋아요를 이미 누른 경우 좋아요를 해제
        else{
            // Place의 likeCount 값 에서 1을 빼준다.
            PlaceRepository.minusLikeCount(PlaceId);
            Love love = result.get();
            loveRepository.delete(love);
            return love.getId();
        }
profile
개발에 재미를 느끼며 꾸준히 성장하는 개발자 김종완 입니다.

1개의 댓글

comment-user-thumbnail
2023년 8월 26일

안녕하세요 firebase 로그인 부분에서 똑같은 에러가 나는데 해결 방법을 자세히 들을 수 있을까요?

답글 달기