[데브코스] Spring Security - 1
Updated: Categories: TILW15D2 - Spring Security 기본구조 / FilterChainProxy에 대해 알아보자.
Spring Security Architecture
기본 구조
- Spring Security는 웹에서의 요청을 받으면 가장 먼저!! 인증과 인가를 수행한다.
- 그 이후 Servlet에 전달하게됨.
- AuthenticationManager : 사용자 인증 관련 처리
- AccessDecisionManager : 사용자가 보호받는 리소스에 접근할 수 있는 적절한 권한이 있는지 확인
FilterChainProxy
- Spring Security는 서블릿 필터
javax.servlet.Filter
의 구현체로 동작한다. @EnableWebSecurity
어노테이션과 함께WebSecurityConfigurerAdapter
추상 클래스를 상속받아 구현함- 웹 요청은 이러한 필터 체인을 차례로 통과하게 됨
- 웹 요청은 모든 필터를 통과하게 되지만, 모든 필터가 동작하는 것은 아님
- 각 필터는 웹 요청에 따라 동작 여부를 결정할 수 있고, 동작할 필요가 없다면 다음 필터로 웹 요청을 즉시 넘김
- 요청을 처리하고 응답을 반환하면 필터 체인 호출 스택은 모든 필터에 대해 역순으로 진행
- 보통 springSecurityFilterChain 이라는 이름으로 Bean 등록됨
- 웹 요청은 이러한 필터 체인을 차례로 통과하게 됨
- Spring Security는 Filter를 잘 이해하고 사용할 수 있어야 함!
- 참고 : 공식문서
필터 종류
- 필터 흐름에 따라 순서가 있다. 주요필터들을 정리해보자면..
필터 | 설명 |
---|---|
ChannelProcessingFilter |
웹 요청이 어떤 프로토콜로 (http 또는 https) 전달되어야 하는지 처리 |
SecurityContextPersistenceFilter |
SecurityContextRepository를 통해 SecurityContext를 Load/Save 처리 |
LogoutFilter |
로그아웃 URL로 요청을 감시하여 매칭되는 요청이 있으면 해당 사용자를 로그아웃 시킴 |
UsernamePasswordAuthenticationFilter |
ID/비밀번호 기반 Form 인증 요청 URL(기본값: /login) 을 감시하여 사용자를 인증함 |
DefaultLoginPageGeneratingFilter |
로그인을 수행하는데 필요한 HTML을 생성함 |
RequestCacheAwareFilter |
로그인 성공 이후 인증 요청에 의해 가로채어진 사용자의 원래 요청으로 이동하기 위해 사용됨 |
SecurityContextHolderAwareRequestFilter |
서블릿 3 API 지원을 위해 HttpServletRequest를 HttpServletRequestWrapper 하위 클래스로 감쌈 |
RememberMeAuthenticationFilter |
요청의 일부로 remeber-me 쿠키 제공 여부를 확인하고, 쿠키가 있으면 사용자 인증을 시도함 |
AnonymousAuthenticationFilter |
해당 인증 필터에 도달할때까지 사용자가 아직 인증되지 않았다면, 익명 사용자로 처리하도록 함 |
ExceptionTranslationFilter |
요청을 처리하는 도중 발생할 수 있는 예외에 대한 라우팅과 위임을 처리함 |
FilterSecurityInterceptor |
접근 권한 확인을 위해 요청을 AccessDecisionManager로 위임 |
ChannelProcessingFilter
- ChannelProcessingFilter 설정을 통해 HTTPS 채널을 통해 처리해야 하는 웹 요청을 정의할 수 있음
- 실제적인 처리를 ChannelDecisionManager 클래스로 위임함
AnonymousAuthenticationFilter
- 비교적 필터체인 마지막에 동작하는 필터
- 해당 필터에 요청이 도달할때까지 사용자가 인증되지 않았다면, 사용자를 null 대신 Anonymous 인증 타입으로 표현
name = anonymousUser
으로 처리한다
AnonymousAuthenticationFilter class
- 인증이 null이면 default값으로 정보를 넣어주는것을 확인할 수 있음
- 아래처럼 이름과 권한을 커스텀할 수 있다.
http.anonymous()
.principal(익명유저 이름 설정)
.authorities(익명유저 권한 설정)
ExceptionTranslationFilter
FilterSecurityInterceptor
바로 위에 위치하며,FilterSecurityInterceptor
실행 중 발생할 수 있는 예외를 잡고 처리함ExceptionTranslationFilter
는 필터체인 실행스택에서 자기 아래에 오는 필터들에서 발생하는 예외들에 대해서만 처리할 수 있다. (따라서 커스텀 필터를 추가해야 하는 경우 커스텀 필터를 적당한 위치에 두어야 한다.)
AuthenticationException
: 인증 관련 예외이며, 사용자를 로그인 페이지로 보냄AccessDeniedException
: 권한 관련 예외,AccessDecisionManager
에 의해 접근 거부가 발생했을 때 접근 거부 페이지를 보여주거나 사용자를 로그인 페이지로 보냄AuthenticationEntryPoint
: 사용자를 정해진 페이지로 포워딩해주는 역할
커스텀
- AccessDeniedHandler를 리턴하는 메소드를 Bean으로 띄워 커스텀이 가능하다
AccessDeniedHandler 작성
@Bean
public AccessDeniedHandler customAccessDeniedHandler() {
return (request, response, e) -> {
...
};
}
exceptionHandling 필터 작성
http.exceptionHandling()
.accessDeniedHandler(customAccessDeniedHandler())
RequestCacheAwareFilter
- 로그인 성공 이후 인증 요청에 의해 가로채어진 사용자의 원래 요청으로 이동하기 위해 사용되는 필터
- 이게 무슨 말일까? 예시를 통해 이해해보자.
예시
- 어떤 익명 사용자가 권한이 필요한 페이지에 접근하려 한다면? 아래와 같은 일이 일어난다.
- 페이지에 접근 권한이 없으므로
ExceptionTranslationFilter
의AccessDenied
에 걸리게 된다. RequestCacheAwareFilter
에 의해 해당 페이지 요청은 캐시에 저장된다.- 마지막으로 default 설정인
/login
으로 리다이렉트 시킴.
- 그리고 사용자가 리다이렉트된 페이지에서 로그인한다면?
- 로그인 후 default 설정은 루트 url
/
로 이동시키는 것이지만, 맨 처음 요청했던 페이지로 이동된다. - 이를 가능하게 하는것이
RequestCacheAwareFilter
의 기능!
- 로그인 후 default 설정은 루트 url