배달의 정석 팀 프로젝트

이상민·2024년 9월 20일
0

오늘부터 배달 앱을 기반으로하는 팀 프로젝트 과제를 시작하게 되었다.

1. 프로젝트

  • 프로젝트 명 : 배달의 정석
  • 소개
    • 한 줄 정리 : 배민을 뛰어 넘는 우리의 배달 어플
    • 내용 : 유저들에게 가게 메뉴를 보여주고 주문을 받고 리뷰를 달 수 있는 기능을 가진 배달 앱을 구현하는 프로젝트
    • 구현 기능
      • 필수 기능
        1. 테스트코드 30% 이상(개인별로 맡은 기능마다 30퍼센트 넘길것)
        2. 가게
        3. 메뉴
        4. 주문
        5. 리뷰
      • 도전 기능
        1. 장바구니
        2. 포인트
        3. 광고
      • 차별화
        1. Redis 사용
        2. AWS 사용 및 배포
        3. Github actions
        4. Docker

2. API 명세서


3. DTO

따로 객체들을 관련 파일 목록을 만들어서 관리했다.

4. ERD

우리 팀원들은 프로젝트 설계를 하는데에 많은 시간을 썼는데 그중에서 특히, ERD를 만들때 정말 많은 시간이 걸렸다

1차 ERD

처음에 설계한 ERD인데 튜터님에게 보여드리고 피드백을 받았다 피드백 내용은
User는 사용자의 고유한 정보만 넣어야하는게 좋으므로, 기존 유저 테이블에 있던 포인트를 따로 테이블로 만들기로 하였고, 주문 테이블 안에 있던 주문 상태와 배달 상태가 모호해서 따로 배달 테이블을 만들어서 분리하기로 하였다. 장바구니에서 id를 따로 받아오지 말고 메뉴 id를 json 형태로 받아오도록 하고 메뉴 테이블에 가게 id값에 연관관계를 갖도록 하였다.

수정 ERD

사용자 인증

JWT 기반 회원가입, 로그인, 탈퇴 기능 구현 과정 기록
이번 프로젝트에서는 Spring Boot와 JWT를 이용해 회원가입, 로그인, 그리고 회원탈퇴 기능을 구현했다. 특히, JWT 토큰을 이용해 인증/인가를 처리하고, 사용자 정보를 기반으로 역할을 관리하는 로직을 작성했다. 과정에서 발생한 문제와 해결 방법을 기록으로 남긴다.

1. 회원가입 및 로그인 기능 구현

회원가입과 로그인 기능은 기본적으로 JWT 토큰을 발급해, 사용자가 로그인하면 이후 요청에서 토큰을 통해 인증할 수 있도록 했다.

  • 회원가입: 사용자가 이메일, 비밀번호, 역할을 입력해 회원가입 요청을 하면, 비밀번호는 암호화되고, 데이터베이스에 저장된다. 이후 JWT 토큰을 발급해 클라이언트에 반환한다.

  • 로그인: 사용자가 입력한 이메일과 비밀번호를 데이터베이스의 정보와 비교해 일치하면, JWT 토큰을 발급하고 반환한다. 이 토큰을 이용해 이후 인증이 필요한 요청에 사용된다.

  • 문제 발생:
    Postman으로 테스트하는 과정에서, 응답 바디에 JWT 토큰을 반환했으나, 클라이언트가 이를 헤더로 전달하지 않아 인증이 되지 않는 문제가 발생했다. 또한, UserRole을 처리하는 과정에서 토큰에 올바르게 담겼음에도 불구하고, "유효하지 않은 UserRole"이라는 오류가 발생했다.

  • 해결 과정:
    JWT 토큰을 응답 바디에 담는 것은 문제가 아니었지만, 인증 시 클라이언트가 이 토큰을 헤더로 전달하지 않는 것이 문제였다. 따라서, Postman에서 Authorization 헤더에 Bearer <JWT 토큰> 형식으로 토큰을 전달하도록 수정했다.

2. 회원탈퇴 기능 구현

  • 상황:
    회원탈퇴 기능은 사용자가 비밀번호를 입력하면 해당 사용자의 비밀번호를 확인한 후, 데이터베이스에서 완전히 삭제하는 방식으로 구현했다. 이때, 탈퇴한 계정은 복구할 수 없도록 처리해야 했다.

  • 과제:
    탈퇴 요청 시 비밀번호를 확인하고, 사용자가 존재하는지 확인한 후, 일치하면 해당 계정을 데이터베이스에서 삭제해야 한다. 예외 처리로는 비밀번호가 일치하지 않거나, 이미 탈퇴된 사용자인 경우를 처리해야 한다.

  • 행동:
    회원탈퇴 요청을 처리하는 컨트롤러는 DELETE 메서드를 사용해 비밀번호만 전달받아 처리했다. 서비스 레이어에서는 사용자의 비밀번호가 일치하는지 확인한 후, 데이터베이스에서 삭제하는 로직을 구현했다.


@Transactional
public void signout(SignoutRequest signoutRequest, Long userId) {
    User user = userRepository.findById(userId).orElseThrow(
        () -> new InvalidRequestException("가입되지 않은 유저입니다.")
    );

    if (!passwordEncoder.matches(signoutRequest.getPassword(), user.getPassword())) {
        throw new AuthException("비밀번호가 일치하지 않습니다.");
    }

    userRepository.delete(user);
}
  • 컨트롤러: @DeleteMapping을 사용해 /auth/signout 엔드포인트로 탈퇴 요청을 처리했다.

  • 서비스: 사용자 비밀번호 검증 후 일치하면 삭제하고, 그렇지 않으면 예외를 던진다.

결과:
회원탈퇴 기능은 Postman으로 테스트했을 때 잘 동작했으며, 비밀번호가 일치하지 않으면 400 에러를 반환하도록 했다. 또한, 사용자가 탈퇴하면 해당 사용자의 데이터는 완전히 삭제되었다.

3. UserRole 처리 문제 해결

  • 상황:
    회원가입, 로그인, 회원탈퇴와 같은 요청을 처리하는 과정에서, UserRoleEnum으로 관리해 역할을 부여하고 검증하는 로직을 작성했다. 그러나 JWT에서 userRole을 추출하는 과정에서 대소문자 문제가 발생했다.

  • 과제:
    JWT에서 추출한 userRole 값이 Enum 클래스에서 정의된 OWNER, USER와 일치하지 않으면 "유효하지 않은 UserRole"이라는 오류가 발생했다.

  • 행동:
    JWT에서 추출한 userRole 값을 toUpperCase()로 변환해 Enum 값과 대소문자 구분 없이 비교하도록 수정했다. 또한, 예외 처리를 추가해 올바르지 않은 userRole 값이 들어올 경우 로그를 남기고 예외를 발생시키도록 했다.

try {
    UserRole userRole = UserRole.valueOf(claims.get("userRole", String.class).toUpperCase());
} catch (IllegalArgumentException e) {
    log.error("Invalid userRole in JWT: {}", claims.get("userRole"));
    throw new AuthException("유효하지 않은 UserRole");
}
  • 결과:
    이후 UserRole과 관련된 문제는 발생하지 않았으며, 클라이언트가 올바르게 USER 또는 OWNER 역할을 부여받고 요청을 처리할 수 있게 되었다.

결론

이번 프로젝트에서 JWT 기반 인증과 회원관리 기능을 구현하면서 발생한 문제들을 해결하며, 인증 토큰 처리, 역할 관리, 그리고 사용자 탈퇴 처리 등 다양한 상황에 대해 깊이 있게 학습할 수 있었다. 특히, JWT 토큰의 생성과 검증 과정에서 발생할 수 있는 다양한 오류를 해결하는 경험이 도움이 되었다. 앞으로 내가 맡은 부분은 광고 부분인데, 최대한 잘 구현해 봐야겠다.

profile
안녕하세요

0개의 댓글