🧐 SecurityBuilder & SecurityConfigurer
SecurityBuilder는 웹 보안을 구성하는 빈 객체와, 설정 클래스들을 생성하는 역할을 수행하며, 그 종류로는 WebSecurity, HttpSecurity가 있습니다.

SecurityConfigurer은 Http 요청과 관련된 보안처리를 담당하는 필터들을 생성하고, 여러 초기화 작업에 관여합니다.

SecurityBuilder는 아래와 같이 SecurityConfigurer를 포함하고 있으며,
인증 및 인가 초기화 작업은 SecurityBuilder 내부에서 SecurityConfigurer를 통해 진행됩니다.

다음과 같이 초기화 작업은 SecurityBuilder의 build() 내부에서 실행되며,


아래와 같이 init()과 configure()을 실행하는 것을 알 수 있습니다.

init()의 내부에서는 SecurityConfigurer의 init()을 호출하며,

configure()의 내부에서는 SecurityConfigurer의 configure()을 호출하는 것을 알 수 있습니다.

AbstractConfiguredSecurityBuilder에는 다음과 같이 apply() 메서드가 정의되어 있습니다.

apply()를 통해 여러 SecurityConfigurer 를 초기화 대상에 추가할 수 있습니다.
이렇게 추가된 SecurityConfigurer는 init()과 configurer()에서 초기화 작업(Filter 생성, Authentication Provider, Authenticaion Manager 등 생성)이 진행됩니다.
최종적으로 WebSecurity의 build()가 반환하는 것은 FilterChainProxy이며,
HttpSecurity의 build()가 반환하는 것은 SecurityFilterChain입니다.
또한 반환된 FilterChainProxy는 SecurityFilterChain을 가지고 있습니다.

이후 사용자 요청이 들어왔을 때, FilterChainProxy는 SecurityFilterChain을 가지고 인증을 수행합니다.
(따로 설정하지 않은 경우) 초기화 작업 실행 시, 우선 WebSecurityConfiguration의 setFilterChainProxySecurityConfigurer()가 호출됩니다.

apply를 통해 WebSecurity에 SecurityConfigurer를 apply해주는 것을 알 수 있습니다.
이후 HttpSecurityConfiguration의 httpSecurity()가 호출됩니다.

이때 위 박스 부분의 코드들로 여러 SecurityConfigurer를 추가하는 것을 알 수 있습니다.
csrf를 예시로 살펴보면, 다음과 같이 Csrf 관련한 SecurityConfigurer인 CsrfConfigurer를 Apply 하는 것을 알 수 있습니다.

위 설정이 끝나면 아래와 같이 여러 설정들이 추가된 것을 알 수 있습니다.

httpSecurity()에서 return된 HttpSecurity는 아래와 같이 SecurityFilterChainConfiguration 에서 build()되어 SecurityFilterChain이 됩니다.

이렇게 만들어진 SecurityFilterChain은 WebSecurityConfiguration의 setFilterChains()로 주입됩니다.

이후 WebSecurityConfiguration의 springSecurityFilterChain()이 호출되었을 때,
위에서 설정된 SecurityFilterChain을 사용하여 이를 반환하는 SecurityFilterChainBuilder를 WebSecurity에 추가합니다.

위에서 추가된 SecurityFilterChainBuilder를 통해 SecurityFilterChain을 생성하여 FilterChainProxy을 생성할 때 주입해줍니다.

🧐 SecurityConfigurer를 직접 만들어 확인해보기
이제 SecurityConfigurer을 직접 만들면서 적용되는 과정을 살펴보도록 하겠습니다.
다음과 같이 SecurityFilterChain을 하나 빈으로 등록합니다.
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain3(HttpSecurity http) throws Exception {
http.authorizeHttpRequests().anyRequest().authenticated();
http.formLogin();
http.apply(new CustomSecurityConfigurer().setFlag(false));
return http.build();
}
}
public class CustomSecurityConfigurer extends AbstractHttpConfigurer<CustomSecurityConfigurer, HttpSecurity> {
private boolean isSecure;
@Override
public void init(HttpSecurity builder) throws Exception {
super.init(builder);
System.out.println("init method");
}
@Override
public void configure(HttpSecurity builder) throws Exception {
super.configure(builder);
System.out.println("configure method");
if (isSecure) {
System.out.println("Https is required");
}
else {
System.out.println("Http is optional");
}
}
public CustomSecurityConfigurer setFlag(boolean isSecure) {
this.isSecure = isSecure;
return this;
}
}
이제 실행시켜 보면 다음과 같은 결과를 얻을 수 있습니다.

🧐 스프링 부트 자동 설정에 의한 초기화 과정
스프링 부트 자동 설정에 의한 초기화 과정을 자세히 살펴보도록 하겠습니다.
우선 SpringWebMvcImportSelector가 실행됩니다.
이때 WebMvcSecurityConfiguration을 로드하는 것을 알 수 있습니다.

이후 SecurityFilterAutoConfiguration 설정 클래스가 실행됩니다.
해당 클래스는 아래와 같이 DelegatingFilterProxyRegistrationBean을 생성하는 것을 알 수 있습니다.

DelegatingFilterProxyRegistrationBean의 역할은 DelegatingFilterProxy를 등록하는 것입니다.
DelegatingFilterProxy는 "springSecurityFilterChain" 이름의 빈을 검색하여, 해당 빈에게 요청을 위임하는 역할을 수행합니다.
이때 "springSecurityFilterChain"이라는 이름을 가진 빈이 바로 FilterChainProxy입니다.
이후 WebMvcSecurityConfiguration가 실행되는데, 다음과 같이 AuthenticationPrincipalArgumentResolver 등을 등록하는 것을 알 수 있습니다.

AuthenticationPrincipalArgumentResolver는 @AuthenticationPrincipal로 Principal 객체를 바인딩 하는데 사용됩니다.
마지막으로 HttpSecurityConfiguration 에서 HttpSecurity를 생성합니다.

이때 Singleton으로 생성하는 것이 아니라 prototype으로 생성하는 것을 알 수 있는데, 그 이유는 HttpSecurity는 여러개를 등록할 수 있기 때문입니다.
HttpSecurity는 공통 설정 클래스(~~Configurer)와, 이를 통해 필터들을 생성하고, 최종적으로 SecurityFilterChain을 반환합니다.

(따로 설정한 것 없이 자동 설정의 경우) 이후 SpringBootWebSecurityConfiguration이 아래 코드를 실행합니다.

이후 WebSecurityConfiguration에서 WebSecurity를 생성하여 내부에서 가지고 있습니다.

위와 같이 WebSecurity는 build() 시 최종적으로 FilterChainProxy를 만듭니다.
WebSecurity에는 securityFilterChainBuilders라는 필드가 있으며,

해당 SecurityBuilder는 SecurityFilterChain를 가지고 있습니다.
그 중 하나가 HttpSecurity(SecurityBuilder)와, 아래 SecurityFilterChain입니다.

이를 가지고 최종적으로 FilterChainProxy를 생성하며, 그 내부에는 SecurityBuilder를 통해 생성한 SecurityFilterChians를 가지고 있게 됩니다.
위 과정을 요약하면 아래와 같습니다.

🧐 WebSecurity와 HttpSecurity의 관계
HttpSecurity는 SecurityFilterChain을 생성합니다.
이러한 SecurityFilterChain은 1개 이상으로 만들어낼 수 있으며,
따라서 HttpSecurity 빈을 싱클톤이 아닌 프로토타입 빈으로 만든 것입니다.
'🏝️ Spring > Security' 카테고리의 다른 글
[Spring Security] @WebMvcTest 작성 시 Spring Security로 인해 발생하는 오류들 (4) | 2022.06.29 |
---|---|
[Security] OAuht2 로그인 - AccessToken을 가지고 로그인하는 방법 (REST API)(카카오, 네이버, 구글) (5) | 2021.12.28 |
[Security] 스프링 시큐리티 - JSON으로 로그인처리 하기 (컨트롤러 사용 X) (15) | 2021.12.12 |
[Security] 스프링 시큐리티 - 로그인(소셜 로그인 포함)성공 시 후처리 하는 방법 (0) | 2021.12.12 |
[Security] 스프링 시큐리티 OAuth2 카카오톡 로그인 구현하기 With Rest API (0) | 2021.12.11 |
🧐 SecurityBuilder & SecurityConfigurer
SecurityBuilder는 웹 보안을 구성하는 빈 객체와, 설정 클래스들을 생성하는 역할을 수행하며, 그 종류로는 WebSecurity, HttpSecurity가 있습니다.

SecurityConfigurer은 Http 요청과 관련된 보안처리를 담당하는 필터들을 생성하고, 여러 초기화 작업에 관여합니다.

SecurityBuilder는 아래와 같이 SecurityConfigurer를 포함하고 있으며,
인증 및 인가 초기화 작업은 SecurityBuilder 내부에서 SecurityConfigurer를 통해 진행됩니다.

다음과 같이 초기화 작업은 SecurityBuilder의 build() 내부에서 실행되며,


아래와 같이 init()과 configure()을 실행하는 것을 알 수 있습니다.

init()의 내부에서는 SecurityConfigurer의 init()을 호출하며,

configure()의 내부에서는 SecurityConfigurer의 configure()을 호출하는 것을 알 수 있습니다.

AbstractConfiguredSecurityBuilder에는 다음과 같이 apply() 메서드가 정의되어 있습니다.

apply()를 통해 여러 SecurityConfigurer 를 초기화 대상에 추가할 수 있습니다.
이렇게 추가된 SecurityConfigurer는 init()과 configurer()에서 초기화 작업(Filter 생성, Authentication Provider, Authenticaion Manager 등 생성)이 진행됩니다.
최종적으로 WebSecurity의 build()가 반환하는 것은 FilterChainProxy이며,
HttpSecurity의 build()가 반환하는 것은 SecurityFilterChain입니다.
또한 반환된 FilterChainProxy는 SecurityFilterChain을 가지고 있습니다.

이후 사용자 요청이 들어왔을 때, FilterChainProxy는 SecurityFilterChain을 가지고 인증을 수행합니다.
(따로 설정하지 않은 경우) 초기화 작업 실행 시, 우선 WebSecurityConfiguration의 setFilterChainProxySecurityConfigurer()가 호출됩니다.

apply를 통해 WebSecurity에 SecurityConfigurer를 apply해주는 것을 알 수 있습니다.
이후 HttpSecurityConfiguration의 httpSecurity()가 호출됩니다.

이때 위 박스 부분의 코드들로 여러 SecurityConfigurer를 추가하는 것을 알 수 있습니다.
csrf를 예시로 살펴보면, 다음과 같이 Csrf 관련한 SecurityConfigurer인 CsrfConfigurer를 Apply 하는 것을 알 수 있습니다.

위 설정이 끝나면 아래와 같이 여러 설정들이 추가된 것을 알 수 있습니다.

httpSecurity()에서 return된 HttpSecurity는 아래와 같이 SecurityFilterChainConfiguration 에서 build()되어 SecurityFilterChain이 됩니다.

이렇게 만들어진 SecurityFilterChain은 WebSecurityConfiguration의 setFilterChains()로 주입됩니다.

이후 WebSecurityConfiguration의 springSecurityFilterChain()이 호출되었을 때,
위에서 설정된 SecurityFilterChain을 사용하여 이를 반환하는 SecurityFilterChainBuilder를 WebSecurity에 추가합니다.

위에서 추가된 SecurityFilterChainBuilder를 통해 SecurityFilterChain을 생성하여 FilterChainProxy을 생성할 때 주입해줍니다.

🧐 SecurityConfigurer를 직접 만들어 확인해보기
이제 SecurityConfigurer을 직접 만들면서 적용되는 과정을 살펴보도록 하겠습니다.
다음과 같이 SecurityFilterChain을 하나 빈으로 등록합니다.
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain3(HttpSecurity http) throws Exception {
http.authorizeHttpRequests().anyRequest().authenticated();
http.formLogin();
http.apply(new CustomSecurityConfigurer().setFlag(false));
return http.build();
}
}
public class CustomSecurityConfigurer extends AbstractHttpConfigurer<CustomSecurityConfigurer, HttpSecurity> {
private boolean isSecure;
@Override
public void init(HttpSecurity builder) throws Exception {
super.init(builder);
System.out.println("init method");
}
@Override
public void configure(HttpSecurity builder) throws Exception {
super.configure(builder);
System.out.println("configure method");
if (isSecure) {
System.out.println("Https is required");
}
else {
System.out.println("Http is optional");
}
}
public CustomSecurityConfigurer setFlag(boolean isSecure) {
this.isSecure = isSecure;
return this;
}
}
이제 실행시켜 보면 다음과 같은 결과를 얻을 수 있습니다.

🧐 스프링 부트 자동 설정에 의한 초기화 과정
스프링 부트 자동 설정에 의한 초기화 과정을 자세히 살펴보도록 하겠습니다.
우선 SpringWebMvcImportSelector가 실행됩니다.
이때 WebMvcSecurityConfiguration을 로드하는 것을 알 수 있습니다.

이후 SecurityFilterAutoConfiguration 설정 클래스가 실행됩니다.
해당 클래스는 아래와 같이 DelegatingFilterProxyRegistrationBean을 생성하는 것을 알 수 있습니다.

DelegatingFilterProxyRegistrationBean의 역할은 DelegatingFilterProxy를 등록하는 것입니다.
DelegatingFilterProxy는 "springSecurityFilterChain" 이름의 빈을 검색하여, 해당 빈에게 요청을 위임하는 역할을 수행합니다.
이때 "springSecurityFilterChain"이라는 이름을 가진 빈이 바로 FilterChainProxy입니다.
이후 WebMvcSecurityConfiguration가 실행되는데, 다음과 같이 AuthenticationPrincipalArgumentResolver 등을 등록하는 것을 알 수 있습니다.

AuthenticationPrincipalArgumentResolver는 @AuthenticationPrincipal로 Principal 객체를 바인딩 하는데 사용됩니다.
마지막으로 HttpSecurityConfiguration 에서 HttpSecurity를 생성합니다.

이때 Singleton으로 생성하는 것이 아니라 prototype으로 생성하는 것을 알 수 있는데, 그 이유는 HttpSecurity는 여러개를 등록할 수 있기 때문입니다.
HttpSecurity는 공통 설정 클래스(~~Configurer)와, 이를 통해 필터들을 생성하고, 최종적으로 SecurityFilterChain을 반환합니다.

(따로 설정한 것 없이 자동 설정의 경우) 이후 SpringBootWebSecurityConfiguration이 아래 코드를 실행합니다.

이후 WebSecurityConfiguration에서 WebSecurity를 생성하여 내부에서 가지고 있습니다.

위와 같이 WebSecurity는 build() 시 최종적으로 FilterChainProxy를 만듭니다.
WebSecurity에는 securityFilterChainBuilders라는 필드가 있으며,

해당 SecurityBuilder는 SecurityFilterChain를 가지고 있습니다.
그 중 하나가 HttpSecurity(SecurityBuilder)와, 아래 SecurityFilterChain입니다.

이를 가지고 최종적으로 FilterChainProxy를 생성하며, 그 내부에는 SecurityBuilder를 통해 생성한 SecurityFilterChians를 가지고 있게 됩니다.
위 과정을 요약하면 아래와 같습니다.

🧐 WebSecurity와 HttpSecurity의 관계
HttpSecurity는 SecurityFilterChain을 생성합니다.
이러한 SecurityFilterChain은 1개 이상으로 만들어낼 수 있으며,
따라서 HttpSecurity 빈을 싱클톤이 아닌 프로토타입 빈으로 만든 것입니다.
'🏝️ Spring > Security' 카테고리의 다른 글
[Spring Security] @WebMvcTest 작성 시 Spring Security로 인해 발생하는 오류들 (4) | 2022.06.29 |
---|---|
[Security] OAuht2 로그인 - AccessToken을 가지고 로그인하는 방법 (REST API)(카카오, 네이버, 구글) (5) | 2021.12.28 |
[Security] 스프링 시큐리티 - JSON으로 로그인처리 하기 (컨트롤러 사용 X) (15) | 2021.12.12 |
[Security] 스프링 시큐리티 - 로그인(소셜 로그인 포함)성공 시 후처리 하는 방법 (0) | 2021.12.12 |
[Security] 스프링 시큐리티 OAuth2 카카오톡 로그인 구현하기 With Rest API (0) | 2021.12.11 |