이번 사이드 프로젝트를 통해 Spring Security 를 사용해보았습니다.
Spring Security
Spring Security is a framework that provides authentication, authorization, and protection against common attacks. With first class support for securing both imperative and reactive applications, it is the de-facto standard for securing Spring-based applications.
For a complete list of features, see the Features section of the reference.Authentication
Spring Security provides comprehensive support for authentication. Authentication is how we verify the identity of who is trying to access a particular resource. A common way to authenticate users is by requiring the user to enter a username and password. Once authentication is performed we know the identity and can perform authorization.
Spring Security provides built-in support for authenticating users. This section is dedicated to generic authentication support that applies in both Servlet and WebFlux environments. See the sections on authentication for Servlet and WebFlux for details on what is supported for each stack.Authorization
Spring Security provides comprehensive support for authorization. Authorization is determining who is allowed to access a particular resource. Spring Security provides defense in depth by allowing for request based authorization and method based authorization.
Authentication : 신원 확인 ex) 로그인
Authorization : 해당 인원의 접근 권한 확인 ex) 로그인한 사용자가 관리자인지 아닌지 확인
인증( Authentication ), 인가 ( Authorization ) 및 보안 기능을 제공하는 Spring 하위 프레임 워크를 말합니다.
Spring Security Architecture Reference
DelegatingFilterChain, FilterChainProxy Reference
A Review of Filters
Spring Security’s Servlet support is based on Servlet Filters, so it is helpful to look at the role of Filters generally first. The following image shows the typical layering of the handlers for a single HTTP request.The client sends a request to the application, and the container creates a FilterChain, which contains the Filter instances and Servlet that should process the HttpServletRequest, based on the path of the request URI. In a Spring MVC application, the Servlet is an instance of DispatcherServlet. At most, one Servlet can handle a single HttpServletRequest and HttpServletResponse. However, more than one Filter can be used to:
Prevent downstream Filter instances or the Servlet from being invoked. In this case, the Filter typically writes the HttpServletResponse.
Modify the HttpServletRequest or HttpServletResponse used by the downstream Filter instances and the Servlet.The power of the Filter comes from the FilterChain that is passed into it.
사용자가 어플리케이션에 요청할 때마다 Servlet 객체와 Filter 들이 포함된 FilterChain 을 생성합니다.
해당 Servlet 객체는 DispatchatcherSerlvet 의 인스턴스임으로
사용자가 요청하기 전 Filter 가 먼저 작동하는 것을 알 수 있습니다.
즉, SpringSecurity 는 Servlet 에 요청이 도달하기 전에 인증, 인가 및 보안 기능을 수행합니다.
그렇다면 Spring Security 의 Filter 에 대해서 알아봅시다!
DelegatingFilterProxy
Spring provides a Filter implementation named DelegatingFilterProxy that allows bridging between the Servlet container’s lifecycle and Spring’s ApplicationContext. The Servlet container allows registering Filter instances by using its own standards, but it is not aware of Spring-defined Beans. You can register DelegatingFilterProxy through the standard Servlet container mechanisms but delegate all the work to a Spring Bean that implements Filter.Here is a picture of how DelegatingFilterProxy fits into the Filter instances and the FilterChain.DelegatingFilterProxy looks up Bean Filter0 from the ApplicationContext and then invokes Bean Filter0.
FilterChainProxy
Spring Security’s Servlet support is contained within FilterChainProxy. FilterChainProxy is a special Filter provided by Spring Security that allows delegating to many Filter instances through SecurityFilterChain. Since FilterChainProxy is a Bean, it is typically wrapped in a DelegatingFilterProxy.
The following image shows the role of FilterChainProxy.
Servlet Container 의 생명주기와 Spring Application Context 를 브릿징을 허용해주는 Spring 에서 제공하는 Filter 입니다.
Servlet Filter 에도 Spring 기술을 사용하기 위해서 Filter 를 Spring Bean 으로 만들어 주입받아서 사용할 수 있게 구성했습니다.
하지만 이렇게 만들어진 Filter 는 Spring Bean 으로만 등록이 되어있기 때문에 필터로써의 역할을 할수 없습니다.
따라서 Servlet Filter 중에서 Servlet Filter 와 Spring Bean 으로 등록된 필터를 연결시켜주는 필터가 필요하고,
그 필터가 DelegatingFilterProxy 입니다.
DelegatingFilterProxy 에서 호출된 Spring Bean 이자 Filter 입니다. Spring Security 에서 제공하는 Filter 이며
Spring Bean 이면서 Servlet Filter 를 구현합니다. SecurityFilterChain 을 호출하여 인증/ 인가 및 보안 기능을 수행합니다.
Servlet 과 Security Filter 의 경계 역할을 하고,
어떤 Spring Security Filter Chain 을 사용할 지 결정합니다.
필터는 순차적으로 실행되며, 마지막 필터까지 예외가 발생하지 않으면 요청을 다시 DispatchServlet 으로 넘깁니다.
@AutoConfiguration(after = SecurityAutoConfiguration.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(SecurityProperties.class)
@ConditionalOnClass({ AbstractSecurityWebApplicationInitializer.class, SessionCreationPolicy.class })
public class SecurityFilterAutoConfiguration {
private static final String DEFAULT_FILTER_NAME = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME;
@Bean
@ConditionalOnBean(name = DEFAULT_FILTER_NAME)
public DelegatingFilterProxyRegistrationBean securityFilterChainRegistration(
SecurityProperties securityProperties) {
DelegatingFilterProxyRegistrationBean registration = new DelegatingFilterProxyRegistrationBean(
DEFAULT_FILTER_NAME);
registration.setOrder(securityProperties.getFilter().getOrder());
registration.setDispatcherTypes(getDispatcherTypes(securityProperties));
return registration;
}
private EnumSet<DispatcherType> getDispatcherTypes(SecurityProperties securityProperties) {
if (securityProperties.getFilter().getDispatcherTypes() == null) {
return null;
}
return securityProperties.getFilter()
.getDispatcherTypes()
.stream()
.map((type) -> DispatcherType.valueOf(type.name()))
.collect(Collectors.toCollection(() -> EnumSet.noneOf(DispatcherType.class)));
}
}
* @author Rob Winch
* @author Keesun Baik
*/
public abstract class AbstractSecurityWebApplicationInitializer implements WebApplicationInitializer {
private static final String SERVLET_CONTEXT_PREFIX = "org.springframework.web.servlet.FrameworkServlet.CONTEXT.";
public static final String DEFAULT_FILTER_NAME = "springSecurityFilterChain";
private final Class<?>[] configurationClasses;
/**
/**
* Uses a {@link WebSecurity} to create the {@link FilterChainProxy} that performs the web
* based security for Spring Security. It then exports the necessary beans. Customizations
* can be made to {@link WebSecurity} by implementing {@link WebSecurityConfigurer} and
* exposing it as a {@link Configuration} or exposing a {@link WebSecurityCustomizer}
* bean. This configuration is imported when using {@link EnableWebSecurity}.
*
* @author Rob Winch
* @author Keesun Baik
* @since 3.2
* @see EnableWebSecurity
* @see WebSecurity
*/
@Configuration(proxyBeanMethods = false)
public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
...
/**
* Creates the Spring Security Filter Chain
* @return the {@link Filter} that represents the security filter chain
* @throws Exception
*/
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
boolean hasFilterChain = !this.securityFilterChains.isEmpty();
if (!hasFilterChain) {
this.webSecurity.addSecurityFilterChainBuilder(() -> {
this.httpSecurity.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated());
this.httpSecurity.formLogin(Customizer.withDefaults());
this.httpSecurity.httpBasic(Customizer.withDefaults());
return this.httpSecurity.build();
});
}
for (SecurityFilterChain securityFilterChain : this.securityFilterChains) {
this.webSecurity.addSecurityFilterChainBuilder(() -> securityFilterChain);
}
for (WebSecurityCustomizer customizer : this.webSecurityCustomizers) {
customizer.customize(this.webSecurity);
}
return this.webSecurity.build();
}
- Spring Application 실행 시 SecurityFilterAutoConfiguration 클래스가 호출되고
- DelegatinFilterProxyRegistrationBean 이 생성 될 때 "springSecurityFilterChain" 라는 이름으로 생성됩니다.
Spring Security 는 Filter 를 사용하여 인증 인가 보안 등의 기능을 제공하는 프레임 워크이며, DelegatingFilterProxy 를 통해 Spring Bean 으로 등록된 필터 ( FilterChainProxy ) 를 호출하여 Spring Security 기능을 수행
다음에는 SecurityFilterChain 에 대해서 알아보겠습니다!