728x90
반응형
SMALL
이번에는, Spring Security가 기본적으로 제공하는 여러 필터들 외에 개발자가 원하는 입맛에 맞게 구현된 필터를 등록하는 방법을 알아보자.
참고로, 필터를 만들기 위해선 Filter를 구현하면 된다.
원하는 커스텀 필터 만들기
StopWatchFilter
package cwchoiit.springsecurity.filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StopWatch;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
@Slf4j
public class StopWatchFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
StopWatch stopWatch = new StopWatch(request.getServletPath());
stopWatch.start();
filterChain.doFilter(request, response);
stopWatch.stop();
log.info(stopWatch.shortSummary());
}
}
- OncePerRequestFilter를 상속받은 StopWatchFilter이다. OncePerRequestFilter는 결국 Filter를 구현한 클래스이다. 그래서 이 OncePerRequestFilter를 상속받아도 필터로 동작한다.
- OncePerRequestFilter는 요청 하나 당 한번만 동작하는 필터이다.
- 요청이 들어오고 요청에 대한 응답을 처리하기까지의 과정에 대한 시간을 기록하는 필터이다.
- 이렇게 원하는대로 필터를 만들면 된다.
이렇게 필터를 만들었으면, 필터를 등록하면 된다.
커스텀 필터 등록하기
지금까지 사용해왔던 Spring Security 설정 클래스에 이 필터를 등록하면 된다. 그게 다음 코드이다.
SecurityConfig
package cwchoiit.springsecurity.config;
import cwchoiit.springsecurity.filter.StopWatchFilter;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.addFilterBefore(new StopWatchFilter(), WebAsyncManagerIntegrationFilter.class)
.httpBasic(AbstractHttpConfigurer::disable) // HTTP Basic authentication disabled
.csrf(AbstractHttpConfigurer::disable) // CSRF protection disabled
.rememberMe(configurer -> configurer.tokenValiditySeconds(86400)) // 1 day
.authorizeHttpRequests(authorizeRequests -> authorizeRequests
.requestMatchers("/home", "/h2-console/**", "/css/**", "/js/**", "/images/**", "/login", "/user/signup").permitAll()
.requestMatchers("/note").hasRole("USER")
.requestMatchers("/admin").hasRole("ADMIN")
.requestMatchers(HttpMethod.POST, "/notice").hasRole("ADMIN")
.requestMatchers(HttpMethod.DELETE, "/notice").hasRole("ADMIN")
.anyRequest().authenticated())
.headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin)) // H2-Console iframe 정상 작동 (Origin 비교 후 같으면 그 iframe 요청은 허용)
.formLogin(formLogin -> formLogin
.loginPage("/login")
.defaultSuccessUrl("/home")
.permitAll())
.logout(logout -> logout
.logoutRequestMatcher(new AntPathRequestMatcher("/user/logout"))
.logoutSuccessUrl("/login"));
return http.build();
}
}
- 여기서 필터를 등록한 부분은 딱 이 부분이다.
http.addFilterBefore(new StopWatchFilter(), WebAsyncManagerIntegrationFilter.class)
- addFilterBefore()는 원하는 필터를 지정한 필터보다 더 앞 순서로 등록하는 것이다. 이 코드를 예로 들면, 내가 만든 StopWatchFilter를 등록할건데 이 필터는 Spring Security에서 등록된 필터 중 가장 첫번째 순서로 알려져 있는 WebAsyncManagerIntegrationFilter보다 더 앞으로 등록해서 가장 앞에 필터를 등록한다.
- addFilterAfter(), addFilterAt(), addFilter() 메서드도 있다. addFilterAfter()는 지정한 필터 바로 다음에 등록하는 것이다. addFilter()는 순서와 상관없이 그냥 필터를 등록하는 가장 단순한 방법이다. 그럼 addFilterAt()은 뭘까?
addFilterAt()은 등록하고자 하는 필터를 가지고 지정한 필터를 대체하는 것이다. 예를 들어 다음코드를 보자.
http.addFilterAt(new MyCustomFilter(), UsernamePasswordAuthenticationFilter.class);
- 이렇게 작성했다면, MyCustomFilter를 등록할건데 그 필터가 UsernamePasswordAuthenticationFilter의 위치에 등록되는 것이고 UsernamePasswordAuthenticationFilter 필터를 대체한다. 그러니까 더 이상 기존의 UsernamePasswordAuthenticationFilter는 동작하지 않는것이다.
이렇게 여러 방법으로 필터를 등록할 수 있다. 그리고 커스텀 필터 만드는 게 이렇게 쉽다.
728x90
반응형
LIST
'Spring Security' 카테고리의 다른 글
Spring Security Part.3 - 테스트 코드 작성 (0) | 2024.10.06 |
---|---|
Spring Security Part.2 - Spring Security Configuration (5) | 2024.10.06 |
Spring Security Part.1 - 내부 구조 파악, Spring Security가 사용하는 여러 필터들 (0) | 2024.10.03 |