스파르타 코딩클럽_ 내일 배움 캠프 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())));
}
}
이렇게 필수 구현기능 테스트 + 문제 해결까지 빠르게 완료되었다.
'🏕️내일배움캠프 > 📂뉴스 피드 프로젝트(23.06.30)' 카테고리의 다른 글
뉴스 피드 프로젝트 6일차_코드 발표 및 회고 (0) | 2023.07.07 |
---|---|
뉴스 피드 프로젝트 5일차_ERD, API 수정, 코드 리뷰 및 발표 준비 (0) | 2023.07.07 |
뉴스 피드 프로젝트 4일차_추가 기능 구현 (0) | 2023.07.05 |
뉴스 피드 프로젝트 2일차_필수 구현 기능 코드 작성 (0) | 2023.07.03 |
뉴스 피드 프로젝트 1일차_S.A와 와이어프레임 제작,ERD 설계, API 명세 작성 (0) | 2023.07.03 |