
웹 애플리케이션에서 로그인 폼은 사용자가 가장 먼저 맞이하는 관문이다.
Spring Security는 .formLogin()만으로 이 로그인 과정을 손쉽게 구현할 수 있도록 도와준다.
이 뒤에는 아주 체계적인 인증 흐름과 여러 필터들이 내부적으로 동작한다.
오늘은 사용자가 아이디와 비밀번호를 입력하고 '로그인' 버튼을 누르는 순간부터 어떤 일들이 일어나는지, formLogin()의 내부를 공부해서 정리해보겠다.
formLogin()
formLogin()은 이름 그대로 HTTP 폼(Form) 기반의 인증을 활성화하는 API이다.
SecurityConfig 설정에서 이 한 줄을 추가하는 것만으로 Spring Security는 다음과 같은 일을 처리한다.
HttpServletRequest에서 읽어 인증을 시도UsernamePasswordAuthenticationFilter를 활성화만약 인증되지 않은 사용자가 로그인이 필요한 페이지(예: /user)에 접근한다면?
-> 사용자는 여러 보안 필터들을 거쳐 로그인 페이지로 이동한다.
AuthorizationFilter
SecurityFilterChain을 통과하다가 AuthorizationFilter를 만난다. /user 페이지에 접근할 권한이 있는가?"를 검사한다. AccessDeniedException 예외를 발생시킨다.ExceptionTranslationFilter
ExceptionTranslationFilter에 의해 포착된다. AuthenticationEntryPoint
ExceptionTranslationFilter는 '인증'이 필요해서 발생했다고 판단 AuthenticationEntryPoint를 통해 인증 절차를 시작로그인 페이지로 리다이렉트
AuthenticationEntryPoint를 통해 인증을 시작하기 위해 사용자를 로그인 페이지로 리다이렉트formLogin() 커스터 마이징formLogin()에서 인증 성공/실패 시의 동작을 유연하게 설정 가능
.defaultSuccessUrl("/", true): 로그인 성공 시 무조건 지정된 "/" 경로로 이동시킨다..defaultSuccessUrl("/", false): (기본값) 사용자가 원래 가려던 페이지가 있었다면 그곳으로, 없다면 "/" 경로로 이동.successHandler(...): 인증 성공 후 복잡한 로직을 수행하고 싶을 때 사용successHandler를 설정하면 defaultSuccessUrl은 무시됩니다..failureHandler(...):// HttpSecurity 설정 내에서...
.formLogin(form -> form
.successHandler((request, response, authentication) -> {
System.out.println("authentication: " + authentication.getName());
response.sendRedirect("/home");
})
.failureHandler((request, response, exception) -> {
System.out.println("exception: " + exception.getMessage());
response.sendRedirect("/login?error=true");
})
)
UsernamePasswordAuthenticationFilter우리가 .formLogin()을 호출할 때 내부에서는 다음과 같은 필터가 생성된다.
// FormLoginConfigurer.java (간략화)
public FormLoginConfigurer() {
// 폼 인증을 처리할 핵심 필터를 생성합니다.
super(new UsernamePasswordAuthenticationFilter(), null);
usernameParameter("username");
passwordParameter("password");
}
위 코드를 통해 UsernamePasswordAuthenticationFilter가 생성된다. 이 필터가 바로 폼 인증의 실질적인 역할을 수행한다.
/login 경로의 POST 요청을 감지UsernamePasswordAuthenticationToken)을 만든다.AuthenticationManager에게 전달하여 실제 인증 절차를 위임결국, .formLogin()은 이 UsernamePasswordAuthenticationFilter를 손쉽게 설정하고 필터 체인에 추가하기 위한 편리한 API임을 알 수 있다.