Tiny Star

🏕️내일배움캠프/📂뉴스 피드 프로젝트(23.06.30)

뉴스 피드 프로젝트 3일차_필수 구현 기능 코드 테스트 및 추가 기능 구현 시작

청크 2023. 7. 5. 22:22

스파르타 코딩클럽_ 내일 배움 캠프 Spring 트랙 6기

[프로젝트] 뉴스 피드 만들기

2023.06.30 ~ 2023.07.07

 

<프로젝트 정보>

개발도구 : IntelliJ

프로그래밍 언어 : Java

데이터베이스 : MySQL

프레임워크 : Spring

와이어프레임 : Figma

ERD 설계 : ERD Cloud

 

<프로젝트 내용>

3일차 오전에 다들 맡은기능을 거의 다 구현했다.

한 명씩 차례대로 Git에 PR하면서 머지를 시도했고 다섯명 모두 무사히 충돌없이 코드를 합칠 수 있었다. (쾌락!)

 

내가 마지막으로 PR을 했기 때문에 Postman에서 우리 팀의 코드가 동작하는데 문제가 없는지 확인했다.

(물론 팀원들과 함께! 화면 공유도 하고!)

 

API 하나씩 차례대로 테스트 하다보니 잘 동작하는 코드가 대부분이었지만 문제점이 발견되기도 했다.

 

Login API에서 아이디나 비밀번호가 틀렸을 시에 각각 다른 예외메시지를 처리하도록 코드를 작성했으나,

실제 Postman에서는 해당 코드에 적힌 메시지가 아닌 JwtAuthorizationFilter에서 설정된 "토큰이 유효하지 않습니다." 예외메시지가 나왔다.

 

[원래 작성했던 UserService 코드]

    public void login(AuthRequestDto requestDto) {
        String username = requestDto.getUsername();
        String password = requestDto.getPassword();

        // 사용자 확인
        User user = userRepository.findByUsername(username).orElseThrow(
                () -> new IllegalArgumentException(" 등록된 사용자가 없습니다.")
        );

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

 

-> Exception 패키지를 만들어서 JWT 인증에 실패한 경우 처리 될 커스텀 핸들러 클래스와  권한이 없는 사용자 접근 시에 발생하는

예외처리 커스텀 핸들러 클래스를 생성해서 해결했다.

 

[CustomAccessDeniedHandler]

package com.sparta.newspeed.exception;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sparta.newspeed.dto.ApiResponseDto;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
//스프링 애플리케이션 컨텍스트에 CustomAccessDeniedHandler 객체가 생성되어 관리
@Slf4j
@RequiredArgsConstructor
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
    //스프링 프레임워크에서 권한이 없는 사용자 접근 시 발생하는 예외를 처리하는 커스텀 핸들러 클래스
    private final ObjectMapper objectMapper; //JSON 데이터를 Java 객체로 변환하거나 Java 객체를 JSON 데이터로 변환하는 데 사용되는 Jackson 라이브러리의 ObjectMapper 객체
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
        sendErrorResponse(response,"권한이 없습니다.");
    }
    private void sendErrorResponse(HttpServletResponse response, String message) throws IOException {
        response.setCharacterEncoding("utf-8");
        response.setStatus(HttpStatus.FORBIDDEN.value());
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.getWriter().write(objectMapper.writeValueAsString(new ApiResponseDto(message,response.getStatus())));
    }
}

[JwtAuthenticationEntryPoint]

package com.sparta.newspeed.exception;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sparta.newspeed.dto.ApiResponseDto;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
//JwtAuthenticationEntryPoint 객체가 생성되어 관리
@RequiredArgsConstructor
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { // JWT 인증에 실패한 경우 처리하기 위한 커스텀 핸들러
    private final ObjectMapper objectMapper;

    // 인증 예외가 발생했을 때 호출되며, 클라이언트에게 인증에 실패했음을 알리기 위한 응답을 처리
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        sendErrorResponse(response,"인증에 실패하였습니다.");
    }
    private void sendErrorResponse(HttpServletResponse response, String message) throws IOException {
        response.setCharacterEncoding("utf-8");
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.getWriter().write(objectMapper.writeValueAsString(new ApiResponseDto(message,response.getStatus())));
    }
}

 

이렇게 필수 구현기능 테스트 + 문제 해결까지 빠르게 완료되었다.