스프링 시큐리티를 적용하려고 할때 먼저 알면 좋은 컴포넌트들을 알아보자
DelegatingFilterProxy, FilterChainProxy, SecurityFilterChain
스프링 시큐리티는 필터를 통해서 인증과 권한을 체크한다. 여기서 필터는 서블릿컨테이너에서 관리하는 서블릿 필터와 스프링컨테이너에서 관리하는 필터 두가지가 있다. 서블릿필터에서는 스프링의 빈을 사용하지 못하기 때문에 스프링은 서블릿필터에서 스프링 빈을 사용할수 있는 DelegatingFilterProxy를 서블릿 필터로 등록을 해둔다.
DelegationFilterProxy는 다시 FilterChainProxy라는 스프링 시큐리티에서 사용하는 필터에 위임을 하고 이 필터에는 filterChain이라는 변수가 있는데 이변수는 SecurityFilterChain의 리스트를 가지고 있으면 다시 SecurityFilteChain안에는 Security에서 사용할 필터들의 리스트를 가지고 있다.
다시 말하면 FilterChainProxy는 SecurityFilterChain의 리스트를 가질수 있고, SecurityFilterChain은 여러개의 필터를 가질수 있다는 말이다.
그림으로 표현하면 다음과 같다.
또 SecurityFilterChain이 여러개가 있을수 있다 그림은 다음과 같다. /api/** url로 접근시에는 SecurityFilterChain0 에 정의된 필터들을 이용하고, 그외 모든 url /**로 접근시에는 SecurityFilterChain n에 정의된 필터들을 이용한다.
아무 설정을 하지 않을경우 SecurityFilterChain에 기본적으로 셋팅되는 필터들이다.
- WebAsyncManagerIntegrationFilter: 스프링웹과 SecurityContext간의 통합을 제공
- SecurityContextPersistenceFilter: SecurityContext 객체를 생성 저장, 인증성공후 세션에 저장
- HeaderWriterFilter: 응답 헤더에 시큐리티 관련 헤더를 추가하는 필터
- CsrfFilter: csrf공격을 방어하는 필터, form 인증시 사용, 모든 요청에 랜덤하게 생성된 csrf토큰을 요구하여, 서버토큰과 비교함, 일치하지 않으면 실
- LogoutFilter: 로그아웃관련 처리를 하는 필터
- UsernamePasswordAuthenticationFilter: 아이디/비밀번호 로그인시 인증 관련 처리하는 필터
- DefaultLoginPageGeneratingFilter: 기본 로그인 페이지 생성 필터
- DefaultLogoutPageGeneratingFilter: 기본 로그아웃 페이지 생성필터
- BasicAuthencationFilter: HttpBasic 인증을 처리
- RequestCacheAwareFilter: 현재 요청에 캐시 요청이 있는지 확인 및 처리
- SecurityContextHolderAwareRequestFilter:
- AnonymousAuthenticationFilter: SecurityContext에 Authentication이 널일경우 AnonymousAuthentication을 만들어주는 필터
- SessionManagementFilter: 세션관련 변조방지, 유효하지 않는 세션 체크, 동시성 제어, 세션생성전략 설정등을 하는 필터
- ExceptionTranslationFilter: AuthenticationException, AccessDeniedException 발생시 처리하는 필터
- FilterSecurityInterceptor: 마지막으로 실행되는 필터이며 리소스에 대한 접근이 가능한지 체크하여 처리하는 필터
위에 나열된 필터들이 순서대로 실행되면서 스프링시큐리티에서 인증 및 권한부여관련 처리와 보안관련된 처리를 한다.
SecurityContextHolder, SecurityContext, Authentication, GrantedAuthority
인증사용자의 정보를 저장하거나 불러오는 관련된 클래스 이다.
SecurityContextHolder에 SecurityContext가 저장되고, SecurityContext에 Authentication이 저장된다.
SecurityContextHolder
SecurityContext는 기본적으로 ThreadLocal에 저장이 된다. 그래서 해당 스레드의 다른 인스턴스에서 인증정보가 필요할때 ThreadLocal에 저장된 SecurityContext에서 인증정보를 가져올수 있게 한다. SecurityContextHolder에 SecurityContextHolderStrategy 인터페이스변수가 선언되어 있는데 이 인터페이스를 구현한 ThreadLocalSecurityContextHolderStrategy 기본적으로 사용한다.
인증 정보를 감싸서 인증한 사용자의 상세정보를 저장한다.
SecurityContext context = SecurityContextHolder.createEmptyContext();
Authentication authentication = new TestingAuthenticationToken("username", "password", "ROLE_USER");
context.setAuthentication(authentication);
SecurityContextHolder.setContext(context);
인증된 사용자의 정보를 가져온다.
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
String username = authentication.getName();
Object principal = authentication.getPrincipal();
Collenction<? extends GrantedAuthority> authorities = authentication.getAuthorities();
SecurityContext
SecurityContext는 인터페이스이다. 이 인터페이스를 구현한 SecurityContextImpl이라는 클래스를 기본으로 사용한다.
Authentication 객체를 가지고 있다.
Authentication
Authentication도 인터페이스이다. 이 인터페이스를 추상클래스로 구현한 AbstractAuthenticationToken을 상속한 UsernamePasswordAuthenticationToken클래스를 기본적으로 사용한다.
현재 인증된 사용자를 나타내며 다음과 같은 속성이 있다.
- principal
- credential
- GrantedAuthorities
GrantedAuthority
GrantedAuthority는 사용자에게 부여한 권한을 나타내는 인터페이스이다. 이 인터페이스를 구현한 SimpleGrantedAuthority를 기본적으로 사용한다. role라는 문자열변수를 가지며 'ROLE_' 접두사를 가지고 권한을 나타낸다.
GrantedAuthority는 Authentication.getAutihorites()로 접근할수 있으며 GrantedAuthority의 Collection을 반환한다.
AuthenticationManager, ProviderManager, AuthenticationProvider
AuthenticationManager
사용자의 인증정보를 검증하고 Authenticaiton 객체를 생성한다.
ProviderManger
가장 많이 쓰이는 AuthenticationManger의 구현체이다. ProviderManager는 인증처리부분을 AuthenticationProvider 리스트에 위임함다.
다음 그림과 같은 구조이다.
AuthenticaionProvider
ProviderManger에는 여러개의 AuthenticationManger를 주입할수 있다. 그리고 각각의 AuthenticaionProdiver는 인증하는 방식이 다르다. 예를들면 DaoAuthenticationProvider는 이름/비밀번호 기반인증을 처리하고, JwtAuthenticatinoProvider는 JWT토큰관련 인증을 처리한다.
UserDetails, UserDetailService
유저의 정보를 저장하고, 유저명으로 유저를 찾는다.
UserDetails
UserDetailService에서 loadUserbyUsername() 메서드의 반환값으로 유저의 정보를 표현하는 인터페이스이다
UserDetailsSevice
인터페이스이며 loadUserByUsername을 구현한 클래스에서 유저를 검색해서 UserDetails를 반환한다. 유저를 검색하지 못한경우 UsernameNotFountException을 던진다. Authentication 의 authenticate의 메소드 실행시 이서비스의 구현체를 이용해서 유저정보를 검색하고 유저를 반환하는 역할을 한다.
AccessDecisionManager, AccessDecisionVoter
사용자의 리소스에 대한 접근을 제어한다. AccessDecisionManager decide 메소드를 실행하면 리스트에 저장된 voter(AccessDesionVoter 구현체들)에게 접근여부를 체크한다.
AccessDecisionManager
리소스에 대한 접근제어를 결정하는 역할을 한다.
- AffirmativeBased: 하나라도 접근권한이 있으면 접근을 허용한다.
- ConsensusBased: 다수결로 접근권한을 결정한다.
- UnanimousBased: 만장일치로 접근권한을 결정한다.
AccessDecisionVoter
AccessDecisionManage에서 decide메소드 실행시 voter리스트를 가져와서 실행는 클래스로 접근권한을 허용할지 체크하고 다음 값중 하나는 반환한다.
- ACCESS_GRANTED: 접근권한
- ACCESS_DENIED: 접근거부
- ACCESS_ABSTAIN: 접근보류
기본 Voter
- RoleVoter: 사용자가 'ROLE_' 로 시작하는 역할을 가졌는지 확인하는 보터
- AuthenticatedVoter: IS_AUTHENTICATION_FULLY, IS_AUTHENTICATION_REMEMBERED, IS_AUTHENTICATION_ANONYMOUSLY 를 체크해서 접근을 승인한다.
- WebExpressionVoter: AccessDecisionVoter에서 기본으로 사용하는 Voter, 'ROLE_' 로 시작하는 역할을 가졌는지 확인하는 보터(그러면 RoleVoter와 차이점은 뭐지?)
설정관련
SpringbootWebSecurityConfiguration
스프링부트에서 스프링시큐리티 설정을 하지 않은 경우, 자동으로 기본설정을 해준다.
@Configuration(proxyBeanMethods = false)
@ConditionalOnDefaultWebSecurity
@ConditionalOnWebApplication(type = Type.SERVLET)
class SpringBootWebSecurityConfiguration {
@Bean
@Order(SecurityProperties.BASIC_AUTH_ORDER)
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated().and().formLogin().and().httpBasic();
return http.build();
}
}
SecutiryFilterAutoConfiguration
스프링부트에서 'springSecurityFilterChain'이라는 이름의 필터를 자동으로 생성해준다.
마치며
더 많은 컴포넌트가 있지만 이번에는 여기까지 정리하기로 하고, 이상 스프링 시큐리티에서 관리하는 주요 컴포넌트에 대해서 알아 보았다. 스프링 시큐리티는 인증과 권한부여에 관련된 프레임 워크로 상당히 방대하고 복잡하여 한번에 이해하기 어려운 프레임 워크이다. 그래서 한번 샘플만 작성해보는 걸로는 부족하다. 그래서 관련 정보를 찾고 이해하는 중에 주요 컴포넌트에대해서 간단히 정리를 해보았다.
참조:
시큐리티 정리 yaho1024 (INCHEOL'S) - velog
로그인 과정으로 살펴보는 스프링 시큐리티 아키텍처(Spring Security Architecture)
Spring Security (1) - FilterChainProxy
[스프링 시큐리티] DelegatingFilterProxy & FilterChainProxy
Spring Security - 2. FilterChainProxy 알아보기
그외 다수 블로그들...
'웹개발 > 스프링시큐리티' 카테고리의 다른 글
5. 스프링 시큐리티 - Remember Me 기능 구현 (0) | 2021.04.19 |
---|---|
4. 스프링 시큐리티 - 회원가입 (0) | 2021.04.19 |
3. 스프링 시큐리티 - h2base 적용하기 (0) | 2021.04.17 |
2. 스프링시큐리티 - 로그인 페이지 변경 (0) | 2021.04.15 |
1. 스프링 시큐리티 - 기본 로그인 (1) | 2021.04.12 |