Spring/문제 해결 (Troubleshooting)

Spring Security 에러 핸들링 오류 해결, /error 접근 권한 문제

가지코딩 2025. 5. 29. 12:35

문제 상황

  1. jwt Filter 와 Spring Security 를 문제 없이 통과함
  2. 컨트롤러와 서비스에 잘 도달
  3. 서비스의 비즈니스 로직에서 예외 발생 (비밀번호 오류 시 예외 처리)
  4. 응답 메시지에 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()));
    }
}