본문 바로가기

프로젝트일지

[Inside] Spring Security formLogin 사용 시 입력값 검증

프로젝트의 로그인 방식은 두가지로 이루어진다.

  • 아이디와 패스워드를 입력하는 Form 로그인 방식
  • Google, 네이버를 활용한 소셜 로그인 방식

 

Form 로그인 방식에서는 아래와 같이 Spring Security 에서 formLogin 을 사용해  인증을 수행하고 있다.                             

SecurityConfig 의 configure(HttpSecurity http) 메소드

 

인증을 통해 권한을 얻지 못한 상태에서 권한이 필요한 URL로 접근하면 loginPage()에서 매개변수로 지정한 URL로 리다이렉트 시키고 로그인 페이지를 출력한다. 로그인 페이지의 구성은 아래와 같다.

여기서 회원가입한 아이디와 비밀번호를입력하고 로그인 버튼을 누르면, SecurityConfig에서 loginProcessingUrl("/login")으로 등록한 Url로 Post요청이 이루어진다. 여기서, Spring Security의 AuthenticationFilter가 요청을 인터셉트하여 인증로직을 수행한다.

 

이 과정에서 기본적인 입력에대한 검증도 이뤄진다. 하지만 이 방식에선 Controller를 통해  Spring과 Thymeleaf를 통합하여 검증에 실패한 입력에 대한 메세지를 출력해주는 로직을 수행할 수 없었다. Spring Seucurity에 의해 로그인 요청이 인터셉트 되어 컨트롤러를 거치지 않고 인증과 검증 관련된 로직이 수행되기 때문이다.

 

때문에 두가지의 해결점이 존재했다.

  1. 로그인 요청이 Spring Security의 AuthenticationFilter을 거치기전에 입력값에 대한 검증(공백 체크)
  2. 유효하지 않은 입력 또는 인증 실패 시 컨트롤러로 요청을 보내 Thymeleaf에서 에러 메시지 출력

 

 

입력값 검증

1번 해결점에 대해서는 AuthenticationFilter 입력 검증 필터 보다 먼저 입력을 검증하는 Filter를 등록하는 것이다. 그러기 위해선 AuthenticationFilter가 실행되는 순서를 알아야 했는데, 이는 SecurityProperties 클래스에서 -100임을 알 수 있었다.

 

때문에 입력값을 검증하는 필터를 만들고, 이 필터를 order = -101 로 등록했다.

입력값 검증 필터(아이디 또는 비밀번호가 공백일 때 검증) / 필터 등록

이를 통해 입력에 대해서 직접 만든 필터로 검증이 이루어 지도록 만들 수 있었다.

 

 

 

컨트롤러로 Foward

위에서 만든 LoginValidationFilter를 보면 입력값에 문제가 있을 때 getRequestDispatcher 를 통해 "/login" 경로로 forward 되는 것을 알 수 있다.

/login 으로 foward

이렇게 되면 인증 관련 로직이 실행되지 않고 바로 "/login" 로 등록된 컨트롤러로 요청이 전달된다. 해당 컨트롤러는 아래와 같다.

참고로, 정상적으로 로그인 될 경우 해당 컨트롤러는 호출되지 않는다. 오직 입력 검증이나 인증에 실패했을 때만 호출된다. 이 컨트롤러를 통해 입력값 검증 실패에 메시지를 Thymeleaf를 통해 출력할 수 있는 것이다.

 

인증에 대한 실패에 대해서도 SecurityConfig에서 failureHandler를 등록하여 위 컨트롤러로 foward하도록 했다.

 

 

지금까지 설명한 로직을 간단하게 도식화 하면 아래와 같다.

로그인 요청 검증, 인증 로직

 

이 처리를 통해 아래와 같이 입력값 검증 후에 인증 과정을 수행하고, 실패 사유에 따라 다른 에러메시지를 출력하도록 처리할 수 있었다.

아이디, 패스워드 모두 입력하지 않았을 때      /       아이디만 입력했을 때      /       존재하는 계정이 아닐 때 

 

 

결론

검증 필터를 통해 시큐리티 이전에 검증을 하고, 검증 또는 인증 실패시 컨트롤러로 Foward하는 과정에서,  Spring Security에서 Login Form을 통해서 어떻게 인증이 이루어지는지 대략적으로 이해할 수 있었다. 또 로그인 실패 시에 요청을 foward 하는 로직을 개발하면서 foward와 redirect의 차이를 알 수 있었다.