security 동작 중에 발생하는 예외는
어떻게 처리할 수 있을까?
기존에 사용하는 예외 처리 방법을 사용할 수 있나?
--
평소에는 @ControllerAdvice, @RestControllerAdvice, @ExceptionHandler 를 이용해서 예외처리를 했다.
다만 해당 어노테이션들을 사용하는 방법은 컨트롤러에서 발생하는 예외를 처리하는 방법으로
아직 컨트롤러에 접근하기도 전 단계인 security에서 발생하는 예외는 처리할 수 없다.
2024.01.18 - [Spring Boot 3] - 상태 코드 반환하기
2024.04.24 - [Spring Boot 3] - 전역으로 예외 처리 통일 시키는 방법
--
security에서 발생하는 예외를 처리하는 방법은?
--
security에서 발생하는 예외를 처리하는 방법은 다양하지만
보통 특정 예외 발생시 호출되는 인스턴스를 구현하여 오버라이딩으로 재정의를 하고 security config(시큐리티 설정)파일에 해당 예외처리를 등록하는 방법이 있다.
예외처리 구현 순서
- 예외 발생시 호출되는 인스턴스를 따로 구현 후 해당 예외에 접근할 때 호출되는 메서드를 원하는 동작으로 재정의
- 구현한 예외 클래스를 security config에 등록
--
예시 ) JWT 토큰을 이용하여 권한 접근 예외처리
--
CustomAccessDeniedHandler.java
@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
@Overide
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_FORBIDDEN, "NOT_AUTHORIZATION");
}
}
AccessDeniedHandler는
Spring Security에서 인증된 사용자가 권한이 없는 리소스에 접근하려고 할 때 호출되는 인터페이스이다.
- 요청한 리소스에 접근 권한이 없는 경우 "AccessDeniedException"이 발생하고
"AccessDeniedHandler"는 해당 예외를 처리하여 클라이언트에게 적절한 응답을 반환한다. - "AccessDeniedHandler"에는 단 하나의 메서드인 handle() 메서드가 존재하고
해당 메서드는 HTTP 상태 코드 403과 함께 에러 메시지 등 응답 본문을 JSON 형식으로 응답할 데이터를 설정한다.
이러한 AccessDeniedHandler 인터페이스를 CustomAccessDeniedHandler 클래스를 만들고 해당 클래스에 구현을 했다.
그리고 응답을 처리하기 위해 handle() 메서드를 재정의 하였다.
handle() 메서드의 매개변수
- HttpServletRequest : HTTP 요청에 대한 정보를 제공하는 메서드를 가지고 있는 인터페이스 ()
- HttpServletResponse : HTTP 응답에 대한 정보를 제공하는 메서드를 가지고 있는 인터페이스
- AccessDeniedException : 권한 접근 거부 시 발생하는 예외 객체
응답할 정보를 담고 있는 HttpServletResponse (= response) 에 에러 정보를 담아 응답한다.
- HttpServletResponse.SC_FORBIDEN : 상태 코드 403을 응답
- "NOT_AUTHORIZATION" : 에러 메시지의 값을 "NOT_AUTHORIZATION" 문자열로 응답
SecurityConfig.java
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
. . .
private final CustomAccessDeniedHandler customAccessDeniedHandler;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
. . .
// 접근 권한 설정
http.authorizeHttpRequests(authorize -> {
authorize
// 공통 관리자
.requestMatchers(new AntPathRequestMatcher("/admin/**/view")).hasAnyRole("REPRESENTATIVE", "OPERATOR", "CUSTOMER", "ADMIN")
// 대표
.requestMatchers("/adminIdCheck",
"/adminJoin",
"/admin/admin/List",
"/admin/admin/**",
"/admin/grade/**")
.hasAnyRole("REPRESENTATIVE")
// 운영 관리자
.requestMatchers("/admin/order/**",
"/admin/item/**",
"/admin/category/**")
.hasAnyRole("OPERATOR", "REPRESENTATIVE")
// 고객 관리자
.requestMatchers("/admin/*/announcement/**",
"/admin/*/QAComment",
"/admin/*/comment")
.hasAnyRole("CUSTOMER", "REPRESENTATIVE")
// 회원
.requestMatchers("/member/**")
.hasAnyRole("USER")
.anyRequest().permitAll();}
);
// 접근 권한 예외처리 등록
http.exceptionHandling(exception -> exception.accessDeniedHandler(customAccessDeniedHandler));
return http.build();
}
}
http.exceptionHandling() 메서드는
"HttpSecurity" 객체의 메서드로, 예외 처리와 관련된 설정을 구성하기 위해 사용된다.
(예외 처리 핸들러를 설정할 수 있는 구성 요소를 제공)
exception -> exception.accessDeniedHandler(customAccessDeniedHandler) 코드는
발생한 예외가 "accessDeniedHandler" 라면 (접근 권한 예외) customAccessDeniedHandler를 호출한다.
--
접근 권한 예외처리 동작 흐름
--
- 사용자가 특정 권한만 접근할 수 있는 리소스에 접근 시도
- Spring Security (Filter) 는 해당 사용자의 인증 상태와 권한을 확인
- 사용자 인증은 되었지만 해당 리소스에 접근할 수 있는 권한이 없어서 "AccessDeniedException" 예외 발생
- HttpSecurity 설정 (SecurityConfig 설정) 에서 정의한 AccessDeniedHandler 호출 (customAccessDeniedHandler)
- customAccessDeniedHandler 에서 재정의한 handle() 메서드를 통해 HTTP 응답을 생성 후 응답
--
접근 권한 예외 처리 후 클라이언트에게 전달된 응답 데이터
--
--
+ 추가 ) 인증되지 않은 사용자 접근 예외 처리 추가하기
--
여기서 인증되지 않은 사용자 접근이라는 것은 다양하다.
- 토큰이 없는 경우
- 잘못된 토큰을 요청한 경우
- 유효하지 않은 토큰을 요청한 경우
CustomAuthenticationEntryPoint.java
@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}
AuthenticationEntryPoint는
Spring Security에서 인증되지 않은 사용자가 보호된 리소스에 접근하려고 할 때 호출되는 인터페이스이다.
commence() 메서드는
인증되지 않은 사용자가 보호된 리소스에 접근할 때 호출되는 메서드이다.
SecurityConfig.java
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
. . .
private final CustomAccessDeniedHandler customAccessDeniedHandler;
private final CustomAuthenticationEntryPoint customAuthenticationEntryPoint
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
. . .
http.exceptionHandling(exception -> {
exception.accessDeniedHandler(customAccessDeniedHandler);
exception.authenticationEntryPoint(customAuthenticationEntryPoint);
});
return http.build();
}
}
+ 물론 따로 등록해도 된다.
http.exceptionHandling(exception -> exception.accessDeniedHandler(customAccessDeniedHandler));
http.exceptionHandling(exception -> exception.authenticationEntryPoint(customAuthenticationEntryPoint));
--
소 주제
--
--
--
소 주제
--
--
--
소 주제
--
--
--
소 주제
--
--
--
소 주제
--
--
--
소 주제
--
--
--
소 주제
--
--
--
소 주제
--
--
--
소 주제
--
--
--
소 주제
--
--
--
'Spring Boot' 카테고리의 다른 글
[IntelliJ] finished with non-zero exit value 1 에러 해결 방법 (0) | 2024.11.26 |
---|---|
이메일 발송하기 (Google SMTP Server/ Gmail을 통해 발송하기) (0) | 2024.06.01 |
스케줄러(@Scheduled)를 이용하여 특정 로직을 자동으로 동작하게 하기 (0) | 2024.05.03 |
validation을 이용하여 유효성 검사하기 [ feat. 회원가입 ] (0) | 2024.04.26 |
전역으로 예외 처리 통일 시키는 방법 (0) | 2024.04.24 |