Spring Security 에서 인증 및 권한 부여 과정에서 발생 할 수 있는 예외 상황을 처리하기위한 커스텀 핸들러들을 구현 하는 과정으로,
Spring Security에서는 인증 또는 권한이 거부될 때 발생하는 예외들을 처리할 수 있도록 AuthenticationEntryPoint와 AccessDeniedHandler 인터페이스를 제공한다.
WebSecurityConfig
public class WebSecurityConfig {
private final CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
private final CustomAccessDeniedHandler customAccessDeniedHandler;
private final UserDetailsServiceImpl userDetailsService;
// 접근 제한 페이지 이동 설정
// http.exceptionHandling().accessDeniedPage("/api/user/forbidden");
// 401 Error 처리, Authorization 즉, 인증과정에서 실패할 시 처리
http.exceptionHandling().authenticationEntryPoint(customAuthenticationEntryPoint);
// 403 Error 처리, 인증과는 별개로 추가적인 권한이 충족되지 않는 경우
http.exceptionHandling().accessDeniedHandler(customAccessDeniedHandler);
return http.build();
}
}
CustomAccessDeniedHandle.java
권한부족 403
@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
private static final SecurityExceptionDto exceptionDto =
new SecurityExceptionDto(HttpStatus.FORBIDDEN.value(), HttpStatus.FORBIDDEN.getReasonPhrase());
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException{
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setStatus(HttpStatus.FORBIDDEN.value());
try (OutputStream os = response.getOutputStream()) {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.writeValue(os, exceptionDto);
os.flush();
}
}
}
CustomAccessDeniedHandler는 Spring Security에서 AccessDeniedException이 발생했을 때 처리하는 역할을 합니다. AccessDeniedException은 인증은 성공했지만 권한이 부족한 경우 발생하는 예외입니다.
위의 코드에서는 handle() 메서드를 오버라이드하여 AccessDeniedException이 발생했을 때 처리 로직을 구현하고 있습니다. 주요한 동작은 다음과 같습니다:
응답 상태 코드 및 형식 설정: response.setStatus(HttpStatus.FORBIDDEN.value())를 사용하여 응답 상태 코드를 403 (Forbidden)으로 설정합니다. 또한, response.setContentType(MediaType.APPLICATION_JSON_VALUE)를 사용하여 응답의 컨텐츠 타입을 JSON 형식으로 설정합니다.
응답 작성: response.getOutputStream()을 사용하여 응답의 출력 스트림을 가져옵니다. ObjectMapper를 사용하여 exceptionDto 객체를 JSON 형식으로 변환한 후, 출력 스트림에 작성합니다. 마지막으로, os.flush()를 호출하여 출력 스트림을 비웁니다.
즉, CustomAccessDeniedHandler는 AccessDeniedException이 발생했을 때 클라이언트에게 403 Forbidden 응답을 반환하고, 그에 따른 메시지를 JSON 형식으로 전달합니다. 이를 통해 클라이언트는 권한이 부족한 상태임을 인지하고 적절한 조치를 취할 수 있습니다.
CustomAuthenticationEntryPoint.java
인증이 필요한 자원에 접근할 때 발생하는 예외인 AuthenticationException을 처리하는 역할 401
@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
private static final SecurityExceptionDto exceptionDto =
new SecurityExceptionDto(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase());
@Override
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException authenticationException) throws IOException {
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setStatus(HttpStatus.UNAUTHORIZED.value());
try (OutputStream os = response.getOutputStream()) {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.writeValue(os, exceptionDto);
os.flush();
}
}
}
SecurityExceptionDto.java
package com.sparta.springsecurity.dto;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@NoArgsConstructor
public class SecurityExceptionDto {
private int statusCode;
private String msg;
public SecurityExceptionDto(int statusCode, String msg) {
this.statusCode = statusCode;
this.msg = msg;
}
}