문제 상황
- jwt Filter 와 Spring Security 를 문제 없이 통과함
- 컨트롤러와 서비스에 잘 도달
- 서비스의 비즈니스 로직에서 예외 발생 (비밀번호 오류 시 예외 처리)
- 응답 메시지에 Spring Security의 exceptionHandling - authenticationEntryPoint 예외가 출력됨
[디버깅]
1. Postman 으로 요청을 보냄
2. jwt 검증과 security 를 통과 후 컨트롤러에 도달한 것을 확인
3. 발생한 예외는 security - authenticationEntryPoint 예외 !!!
{
"error": "인증 실패: Full authentication is required to access this resource"
}
* SecurityConfig 의 filterChain 중 예외 핸들링
.exceptionHandling(configurer ->
configurer
.authenticationEntryPoint((request, response, authException) -> {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json;charset=UTF-8");
String message = "{\"error\": \"인증 실패: " + authException.getMessage() + "\"}";
response.getWriter().write(message);
})
.accessDeniedHandler((request, response, accessDeniedException) -> {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response.setContentType("application/json;charset=UTF-8");
String message = "{\"error\": \"접근 거부: " + accessDeniedException.getMessage() + "\"}";
response.getWriter().write(message);
})
)
의문점
Security 를 잘 통과해서,
컨트롤러, 서비스에 잘 도달했고, 서비스에서 예외를 던졌는데
왜 Security 예외가 출력 되는 걸까 ? !!!
대체 왜 🤷♀️🤷♀️🤷♀️🤷♀️🤷♀️
문제점
- 서비스에서 던진 예외를 확인할 수 없음
- 서비스에서 던진 예외는 무시되고, Security - authenticationEntryPoint 예외가 출력 됨
해결 과정
1. application.yml 에서 loggig level 설정
logging:
level:
org:
springframework:
security: trace
* application.properties
logging.level.org.springframework.security = trace
2. 로그 확인
- /api/accounts/password 에서 /error 로 foward 되었고
- /error 접근 중 예외 발생
문제 원인
- Spring MVC는 ResponseStatusException, RuntimeException 등이 발생하면 내부적으로 /error 경로로 forward함
- 그런데 이 /error 경로가 Security에서 보호되고 있었기 때문에,
- 인증이 필요하다고 판단되어, authenticationEntryPoint로 흘러갔고
- 결과적으로 모든 예외가 authenticationEntryPoint 예외로 응답됨
* SecurityConfig 의 filterChain
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/accounts", "/api/accounts/login").permitAll()
.requestMatchers("/api/**").authenticated()
.anyRequest().denyAll()
)
/error 경로가 .anyRequest().denyAll() 에 걸려 접근 불가 가 된 것
해결 방법
1. /error 접근 허용
// 접근 제어
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/accounts", "/api/accounts/login").permitAll()
// /error 접근 모두 허용
.requestMatchers("/error").permitAll()
.requestMatchers("/api/**").authenticated()
.anyRequest().denyAll()
)
결과
잘 해결되었다 !
또 다른 방법은
2. @ControllerAdvice를 사용한 예외 직접 처리
- Spring MVC의 예외 처리 컨트롤러를 만들어 /error 경로 포워딩 자체를 피한다.
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(SomeCustomException.class)
public ResponseEntity<ErrorResponse> handleCustomException(SomeCustomException ex) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(new ErrorResponse("에러 메시지", ex.getMessage()));
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleOtherExceptions(Exception ex) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse("서버 에러", ex.getMessage()));
}
}
'Spring > 문제 해결 (Troubleshooting)' 카테고리의 다른 글
@Cacheable 사용 시 역직렬화 오류 해결 (1) | 2025.07.15 |
---|---|
@ControllerAdvice가 Filter 예외를 잡지 못하는 문제 해결 (0) | 2025.06.04 |
@LastModifiedDate 와 DB의 ON UPDATE CURRENT_TIMESTAMP 동시 사용 문제 (1) | 2025.05.23 |
JPA 변경사항이 즉시 반영되지 않을 때 - 영속성 컨텍스트와 DB 값 불일치 문제 (2) | 2025.05.23 |
Caused by: java.lang.IllegalArgumentException: jdbcUrl is required with driverClassName. (0) | 2025.05.12 |