exceptionHandling()
• 예외 처리는 필터 체인 내에서 발생하는 예외를 의미하며
크게 인증예외(AuthenticationException) 와 인가예외(AccessDeniedException)로 나눌 수 있다
• 예외를 처리하는 필터로서 ExceptionTranslationFilter 가 사용 되며 사용자의 인증 및 인가 상태에 따라
로그인 재시도, 401, 403 코드 등으로 응답할 수 있다
예외 처리 유형
AuthenticationException [ 인증 예외 ]
해당 예외가 발생하면 ExceptionTranslationFilter가 진행하는 과정
1. SecurityContext에서 인증 정보 삭제
기존의 Authentication 이 더 이상 유효하지 않다고 판단하고 Authentication 을 초기화 한다
2. AuthenticationEntryPoint 호출
AuthenticationException 이 감지되면 필터는 authenticationEntryPoint 를 실행하고 이를 통해 인증 실패를 공통적으로
처리할 수 있으며 일반적으로 인증을 시도할 수 있는 화면으로 이동한다
3. 인증 프로세스의 요청 정보를 저장하고 검색
RequestCache & SavedRequest 인증 프로세스 동안 전달되는 요청을 세션 혹은 쿠키에 저장
사용자가 인증을 완료한 후 요청을 검색하여 재 사용할 수 있다. 기본 구현은 HttpSessionRequestCache 이다
AccessDeniedException [ 인가 예외 ]
해당 예외가 발생하면 ExceptionTranslationFilter가 진행하는 과정
AccessDeniedHandler 호출
AccessDeniedException이 감지되면 필터는 사용자가 익명 사용자인지 여부를 판단하고
익명 사용자인 경우 인증예외처리가 실행되고 익명 사용자가 아닌 경우 필터는 AccessDeniedHandler 에게 위임한다
exceptionHandling() API
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.exceptionHandling(exception -> exception
.authenticationEntryPoint((request, response, authException) -> { // 커스텀하게 사용할 AuthenticationEntryPoint 를 설정한다
System.out.println(authException.getMessage());
})
.accessDeniedHandler((request, response, accessDeniedException) -> { // 커스텀하게 사용할 AccessDeniedHandler 를 설정한다
System.out.println(accessDeniedException.getMessage());
})
);
return http.build();
}
AuthenticationEntryPoint 는 인증 프로세스마다 기본적으로 제공되는 클래스들이 설정된다
- UsernamePasswordAuthenticationFIlter가 인증을 처리하다가 실패해서 예외를 던지면
해당 예외를 처리하기위해 LoginUrlAuthenticationEntryPoint가 호출되어 사용자를 로그인 페이지로 리다이렉트시켜서 인증을 다시 시도할 수 있게한다.
- BasicAuthenticationFilter가 HTTP Basic 인증 처리를 하다가 실패해서 예외를 던지면
해당 예외를 처리하기위해 BasicAuthenticationEntryPoint 가 호출되어 사용자를 로그인 페이지로 리다이렉트하는
대신, HTTP 상태 코드 401 (Unauthorized)를 응답으로 반환한다.
- 아무런 인증 프로세스가 설정 되지 않으면 기본적으로 Http403ForbiddenEntryPoint가 사용된다
[ 403 Forbidden 응답이 반환된다. ]
- 사용자 정의 AuthenticationEntryPoint 구현이 가장 우선적으로 수행되며 이 때는 기본 로그인 페이지 생성이 무시된다
AccessDeniedHandler 는 기본적으로 AccessDeniedHandlerImpl 클래스가 사용된다
예시코드)
@EnableWebSecurity
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(auth -> auth
.requestMatchers("/login").permitAll()
.requestMatchers("/admin").hasRole("ADMIN")
.anyRequest().authenticated())
.formLogin(Customizer.withDefaults())
.exceptionHandling(exception -> exception
.authenticationEntryPoint(new AuthenticationEntryPoint() {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
System.out.println("exception = " + exception);
response.sendRedirect("/login");
}
})
.accessDeniedHandler(new AccessDeniedHandler() {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
System.out.println("exception = " + exception);
response.sendRedirect("/denied");
}
})
);
return http.build();
}
ExceptionTranslationFilter
예외처리 흐름도
![15) 예외처리 - exceptionHandling(), ExceptionTranslationFilter - ExceptionTranslationFilter - AccessDeniedException [ 인가 예외 ] - 예외처리 흐름도 15) 예외처리 - exceptionHandling(), ExceptionTranslationFilter - ExceptionTranslationFilter - AccessDeniedException [ 인가 예외 ] - 예외처리 흐름도](https://blog.kakaocdn.net/dn/EbNLA/btsKilERmYl/iZhi3geKxPgDrKxkgK5iC1/img.png)
[사용자는 인증을 받지않은 상태, /user는 ADMIN ROLE을 가진 사용자만 접근 가능한 엔드포인트라고 가정한다.]
AuthorizationFilter는 인가관련 필터이다.
해당 http request를 한 클라이언트의 권한을 가지고 해당 엔드포인트에 접근할 수 있는지 확인한다.
위와같은 가정을 가지므로 AccessDeniedException이라는 인가관련 예외를 던진다.
그 예외를 ExceptionTranslationFilter가 처리한다.
AccessDeniedException가 발생했을때 클라이언트가 익명사용자인지,
기억하기인증 [remeberMe]으로 로그인한건지 판단해서 둘중 하나라도 맞다면 AuthenticationException을 발생시킨다.
기억하기인증[자동로그인]으로 로그인했는데도 불구하고 해당 사용자가 권한이 없다면
AuthenticationException을 발생시키는 이유는 기억하기 인증은 쿠키를 기반으로한 낮은 보안레벨의 인증이기 때문이다.
Remember-Me 로그인 (보안 레벨 낮음):
- 쿠키 기반 자동 인증 방식입니다. 사용자가 로그인할 때 'Remember Me' 옵션을 체크하면 이후 쿠키를 통해 자동으로 인증이 이루어집니다.
- 이 방식은 보안 수준이 낮기 때문에, 중요하지 않은 리소스(일반 콘텐츠 등)에는 접근을 허용할 수 있지만, 중요한 작업에는 제약이 있습니다.
- 중요한 작업(예: 계정 정보 수정, 결제 등)을 시도할 때는 추가 인증을 요구하는 것이 보안적인 관점에서 매우 중요합니다.
자동로그인을 한 사용자가 권한이 있더라도, 해당 작업이 중요한 작업이라면 추가 인증을 요구할 수 도 있다.
[ 설계에 따라 다른듯하다. ]
그래서 결국 AuthenticationException가 발생하면
SecurityContext의 authentication[인증객체]를 null로 설정한다.
HttpSessionRequestCache를 이용하여 Session에 사용자의 요청관련 정보를 저장한다.
AuthenticationEntiryPoint를 통해 인증 실패 이후 작업을 진행한다.
[RequestCache는 인터페이스이고 기본 구현체는 HttpSessionRequestCache 이며
SavedRequest 도 인터페이스이고 기본 구현체는 DefaultSavedRequest 이다.]
HttpSessionRequestCache 는 DefaultSavedRequest 객체를 세션에 저장하는 역할을 하며
DefaultSavedRequest 는 현재 클라이언트의 요청과정 중에 포함된 쿠키, 헤더, 파라미터 값들을 추출하여 보관하는 역할을 합니다.
즉 현재 클라이언트의 요청 과정에서 생성되거나 참조되는 모든 정보는 DefaultSavedRequest 에 저장되고 이 객체는 HttpSessionRequestCache 에 의해 세션에 저장됩니다.
RequestCache와 savedRequest에 대해서 - 인프런 | 커뮤니티 질문&답변
누구나 함께하는 인프런 커뮤니티. 모르면 묻고, 해답을 찾아보세요....
www.inflearn.com
[사용자는 인증을 받은 상태, /user는 ADMIN ROLE을 가진 사용자만 접근 가능한 엔드포인트라고 가정한다.]
이때는 익명사용자도 아니고 , RememberMe[기억하기,자동로그인] 사용자가 아니므로
AccessDeniedHandler가 호출되서 처리된다.
'인프런 > 스프링 시큐리티 완전 정복 [6.x 개정판]' 카테고리의 다른 글
17) 악용보호 - CSRF(Cross Site Request Forgery, 사이트 간 요청 위조) (1) | 2024.10.28 |
---|---|
16) 악용보호 - CORS (1) | 2024.10.25 |
14) 세션관리 - SessionManagementFilter / ConcurrentSessionFilter (1) | 2024.10.23 |
13)세션관리 - 동시 세션 제어 , 세션 고정 보호, 세션 생성 정책 (1) | 2024.10.22 |
12)스프링 MVC 로그인 구현 (1) | 2024.10.21 |
댓글