@Override
protected void configure(final HttpSecurity http) throws Exception {
http
.formLogin()
.loginPage("/login.html")
.loginProcessingUrl("/perform_login")
.defaultSuccessUrl("/homepage.html", true)
//.failureUrl("/login.html?error=true")
.failureHandler(authenticationFailureHandler())
}
Spring Security를 보다보면 위처럼 FormLogin을 통해서 Login 로직을 구성하는 경우가 굉장히 많다.
@Override
protected void configure(final HttpSecurity http) throws Exception {
http
.logout()
.logoutUrl("/perform_logout")
.deleteCookies("JSESSIONID")
.logoutSuccessHandler(logoutSuccessHandler());
}
그리고 Logout도 비슷한 로직으로 설정하는 경우가 많다.
그래서 나도 가독성상 이 두개를 사용해서 config하면 좋을 것 같아서 FormLogin으로 LoginFilter를 구성하고 싶었지만 제대로 작동하지 않았다.. 그런데 Logout은 제대로 작동함…!
그래서 이 둘의 차이점에 대해서 적어보려고 한다.
나의 궁극적인 목적은 FormLogin에서 작동되는 Filter가 내가 Custom한 Filter가 되도록 구성하고 싶었다. (물론 Bean으로 생성해서 addFilter로 구성하는 방법을 알지만 최대한 가독성을 살리고 싶었음)
하지만 구글링을 아무리 해보고 config를 수정해도 당최 작동되지 않았다.. 그래서 결국 Spring Security 코드를 분석하였다.
public FormLoginConfigurer<HttpSecurity> formLogin() throws Exception {
return getOrApply(new FormLoginConfigurer<>());
}
일단 Config에서 FormLogin method를 실행하면 FormLoginConfigurer가 생성된다.
public FormLoginConfigurer() {
super(new UsernamePasswordAuthenticationFilter(), null);
usernameParameter("username");
passwordParameter("password");
}
그러면 이 FormLoginConfigurer은 UsernamePasswordAuthenticationFilter를 생성한다. 이 Filter를 다른 Filter로 구성하는 생성자가 있나 보았지만 이 생성자만 사용한다.
그리고 FormLoginConfigurer은 final class여서 override하지 못하도록 설정되어 있었다.
그러면 AbstractAuthenticationFilterConfigurer 의 authFilter 로 등록되게 되고, authFilter 는 private이다.
protected final void setAuthenticationFilter(F authFilter) {
this.authFilter = authFilter;
}
그리고 이 authFilter를 수정하는 메소드는 protected이기 때문에 내가 구현할 어플리케이션에서 호출할 수 없었다.
혹시나 하는 마음에 메소드를 호출하는 곳들을 찾아봤지만 특정 config에서만 사용된다.
@Bean
public JwtUsernamePasswordAuthenticationFilter loginFilter() throws Exception {
JwtUsernamePasswordAuthenticationFilter filter = new JwtUsernamePasswordAuthenticationFilter();
filter.setFilterProcessesUrl("/**/login");
filter.setAuthenticationManager(super.authenticationManagerBean());
filter.setAuthenticationSuccessHandler(loginSuccessHandler);
filter.setAuthenticationFailureHandler(loginFailureHandler);
return filter;
}
그래서 결국 FormLogin에 CustomFilter는 적용하지 못하고 위처럼 따로 Bean으로 생성해서 UsernamePasswordAuthenticationFilter 전에 등록해야 한다.
구글링하다보면 이걸 혼합해서 사용하는 경우가 있는데 사실 formLogin은 적용안되고 Filter Bean 정의만 적용되는 것..
http.logout()
.logoutUrl("/**/logout")
.addLogoutHandler(logoutHandler)
.logoutSuccessHandler(logoutSuccessHandler)
.permitAll();
로그아웃의 경우는 로직을 모두 Filter가 아닌 handler로 구성한다. 그리고 이 handler를 커스텀할 수 있도록 메소드를 모두 제공한다.
그래서 http.logout()은 동작 handler도 설정할 수 있지만 formLogin은 커스텀 필터를 사용할 수 없다.
'Java > spring' 카테고리의 다른 글
[Spring] WireMock 을 사용한 HTTP Client 유닛테스트 (0) | 2022.12.11 |
---|---|
[Spring] Spring Batch에 Hexagonal Architecture를 적용해보자 (0) | 2022.06.06 |
[Spring] Log4j2를 이용해 로깅해보자 (0) | 2022.05.29 |
[Spring Security] LoginSuccessHandler와 FailureHandler 호출 원리 (0) | 2022.02.19 |
[Spring Cloud] FeignClient Logging 방법 정리 (0) | 2022.02.16 |