AbstractAuthenticationProcessingFilter 클래스를 사용자의 자격증명을 인증하는 기본 필터로 사용한다.UsernamePasswordAuthenticationFilter는 AbstractAuthenticationProcessingFilter를 확장한 클래스로서 HttpServletRequest에서 제출된 사용자 이름과 비밀번호로부터 인증을 수행한다DefaultLoginPageGeneratingFilter 및 DefaultLogoutPageGeneratingFilter가 초기화 된다인증을 처리하는 필터라는 의미를 가지고 있다. 이 필터가 기본 필터로 이번 시간에 우리가 UsernamePasswordAuthenticationFilter 라는 것을 학습할 건데, 이 필터가 바로 AbstractAuthenticationProcessingFilter 를 확장한 클래스다. 상속했다는 것. 그렇기에 이 필터를 통해 HttpServletRequest 요청 객체에서 제출한 사용자 이름, 비밀번호와 같은 정보를 읽어 인증을 수행하는 것. 그리고 인증 프로세스가 초기화될 때 로그인 페이지 생성을 위해서 DefaultLoginPageGeneratingFilter 및 DefaultLogoutPageGeneratingFilter 가 초기화된다. 앞에서 테스트 시 인증을 받기 위해 로그인 페이지와 로그아웃 페이지가 제공(생성) 되었는데 두 개의 페이지 생성을 위해 이 필터들이 작업을 하고 있다. UsernamePasswordAuthenticationFilter 를 통해 Form 로그인 인증을 할 때 이 두 개의 필터도 자동적으로 생성해서 로그아웃 페이지와 로그인 페이지를 제공해준다 보면 된다.

AbstractAuthenticationProcessingFilter 가 클라이언트의 로그인 요청을 받고 있다. 보통은 이 클래스를 확정해서 우리는 인증 처리를 한다. 기본적으로 Spring Security 가 제공하는 클래스가 바로 UsernamePasswordAuthenticationFilter 가 되겠고, 만약 우리가 이 추상 클래스를 직접 상속받아 custom 한 authentication filter 를 만들어 인증 수행을 할 수도 있다. 그 중 AttemptAuthentication 메소드가 있는데 이 메소드를 재정의해야한다. 위에서 이 메소드를 호출해주면 재정의한 밑 구현체 클래스에서 인증을 위한 작업을 기술하면 된다. 그러면 구체적으로 UsernamePasswordAuthenticationFilter 가 인증 처리를 어떻게 하는지에 대한 내용을 흐름들을 토앻 확인해볼 것.

그림을 보면 보면 클라이언트, 사용자가 있고 Get 방식으로 로그인 요청을 하고 있다. 그러면 이 로그인 요청을 아래에 있는 필터가 가로채 인증 처리를 하게 될 것. 그러면 이 필터는 현재 사용자가 Get 방식으로 로그인 요청을 하고 있는데 요청이 인증 처리를 해야 될 요청인지 인증 처리를 할 필요가 없는 요청인지에 대해 검증을 하고 다음 과정을 이어간다. 그래서 맨 처음에 RequestMatcher 가 그 역할을 한다. 이 RequestMatcher 는 요청 정보가 매칭이 되는지 확인한다. 이 말은 기본적으로 RequestMatcher 에는 로그인 정보가 저장되어 있다. 그래서 현재 클라이언트에서 요청한 정보가 자기가 가지고 있는 정보와 일치하면 즉, 매칭이 되면 true 를 반환한다. true 를 반환해야 그때 실제 인증 처리를 계속 이어나갈 수 있는 것. 현재 클라이언트는 로그인으로 요청을 했다. 그리고 현재 기본적으로는 RequestMatcher 가 로그인 정보를 가지고 있다 했다. 그래서 두 개의 정보는 매칭이 된다. 그렇기 때문에 인증을 한다. 만약에 클라이언트가 /login이 아닌 /login-process 이런 식으로 했다면 클라이언트 정보와 RequestMatcher 정보가 맞지 않기에 일치하지 않을 것. 그러면 인증을 하지 않는다. 그렇게 되면 다음 필터로 패스한다. 이게 첫 번째 과정이다.
만약 매칭이 되어 RequestMatcher 가 로그인으로 요청이 되었구나를 보고 다음으로 넘기면 가장 먼저 나오는 객체가 바로 UsernamePasswordAuthenticationToken 이다. Authentication 은 인터페이스로, Spring Security 가 제공하는 인터페이스이며, UsernamePasswordAuthenticationToken 는 이 인터페이스를 구현한 구현체이다. UsernamePasswordAuthenticationToken 도 따로 배울 것이기에 이번 시간에 자세하게 나올 필요하는 없지만 토큰은 인증 처리를 하기 위해 사용되는 인증 객체라 보면 된다. 여기서 맨 처음 어떤 일을 하냐면 이 토큰에 어떠한 정보를 담는다. 어떤 정보를 저장하냐면 username 과 password 를 저장한다. username 과 password 는 사용자가 로그인 할 때 보통 우리가 id, password 이렇게 입력 창이 있는데 이 두 개의 정보를 의미한다. 이 두 개의 정보를 필터가 읽어 꺼내온 다음 토큰에 저장한다. 그러면 이 인증 토큰은 username 과 password 를 가진 채로 인증 수행을 할 수 있도록 사용되어지는 것. 그래서 이 토큰에 userId 와 password 를 생성하고 AuthenticationManager 라는 클래스에 전달한다. 이걸 그래서 이 Manager Class 가 이 토큰을 가지고 실제 인증 처리를 하게끔 하는 것. 우리가 Form 로그인에서 인증 처리를 하는 가장 핵심적인 건 바로 id 와 password 가 현재 DB나 시스템에 저장되어 있는 그 id 와 password 가 같은지 비교한다. 그래서 서로 맞으면 인증이 성공하고 맞지 않으면 실패. 그렇기 때문에 가장 중요한 건 id 와 password 가 인증 처리에 계속 전달되어야 된다. 그래서 AuthenticationManager 가 그 인증 처리를 위한 id, password 가 담긴 토큰을 받아서 인증 처리를 하는 것. 그 이후에도 인증 처리를 하기 위한 많은 과정들이 있다. 우리는 여기에 대해서는 앞으로 계속 학습할 예정.
여기서는 인증 관리자가 어떻게 인증 처리를 한다 그리고 인증 관리자가 인증 처리에 대해서 성공을 했을 경우 그 다음에 실패했을 경우 그 두 가지를 나눠 보도록 할 것. 참고로 지금 나오는 많은 클래스들이 각 챕터마다 학습할 예정이기에 이번 시간에는 전체적인 인증 흐름 속에서 이 클래스가 하는 대략적인 역할만 알면 될 것.
인증에 성공했을 경우를 보자. 필터는 가장 먼저 어떤 일을 하느냐, 물론 필터뿐만 아니라 필터에 사용하는 여러 클래스도 있을 것. 클래스에서 한다 보면 된다. 클래스에서 한다고 보면 된다. 이 필터가 가장 먼저 어떤 일을 하는가 하면 먼저UsernamePasswordAuthenticationToken 를 또 만든다. 초반에도 만들었디만 인증에 최종 성공했을 경우에도 또 만든다. 인증 객체에 또 다른 정보를 담아야 되기 때문에 그 정보는 어떤 정보냐면 바로 UserDetails 타입의 객체 또는 이 타입이 아니더라도 user 객체의 정보가 들어간다. 이제는 인증에 성공했기 때문에 사용자의 이름, 아이디 뿐만 아니라 그 사용자가 가지고 있는 여러가지 정보들을 다 가지고 있어야 한다. 보통은 DB에서 어떤 사용자의 정보를 가져와 객체를 만들 것. 그 객체가 이 곳에 저장이 된다. 또 하나는 권한이다. 사용자가 가지고 있는 권한 정보들이 저장이 된다. 결론적으로 최종 인증에 성공한 사용자의 정보, 권한이 인증 객체에 저장이 된다. 그러면 성공한 인증 객체를 활용해야 할 것.
그 후 SessionAuthenticationStrategy 클래스가 있는데, 이 클래스를 통해 새로운 로그를 알리는 것. 즉, 현재 사용자가 인증해서 성공했다 그렇기에 여기 인증에 성공한 사용자의 세션 관련 작업들을 해야 한다.
그 후 SecurityContextHolder 가 있다. 이 클래스가 조금 중요한데, 최종 인증에 성공한 사용자의 객체나 권한 정보가 담겨있는 인증 객체 (Authentication) 을 SecurityContext 에 설정한다. 또한 HttpSession 에 SecurityContext 가 저장된다. 이 두 작업을 하는 궁극적 이유는 사용자의 인증 상태를 유지하기 위해서이다. 우리가 로그인에 성공했을 시 다른 요청을 보내면 또 로그인을 해야할 필요는 없다. 한 번 로그인에 성공하면 보통 세션이 timeout 이 20분 정보 지나 만료되거나 혹은 아예 어플리케이션이 종료되는 등의 경우에 다시 로그인을 해야지, 그렇지 않으면 한 번 로그인에 성공하면 계속 인증 상태에 유지되어 그 다음부터는 요청만으로 인증 상태에서 활동해야 할 것. 즉, 인증 상태가 유지되어야 한다. 그렇기에 두 가지 작업이 바로 인증 상태를 유지하기 위해서 존재하는 것. 로그인에 성공한 이후에 보통 세션이 타임아웃이 20분 정도 만료되거나 아니면 아예 어플리케이션이 종료되거나 그럴 경우에 다시 우리가 로그인 해야지 그렇지 않으면 한 번 로그인 성공하면 계속 인증 상태가 유지되어 그 다음부터는 요청해 인증 상태에서 계속 활동해야 된다. 인증 상태가 유지되는 중. 그때 가장 필요한 클래스가 SecurityContextHolder 이고 SecurityContext 이다. 이 두 개의 클래스는 사용자 인증 상태를 유지하기 위해 필요한 클래스라 보면 된다. 이후에 더 자세히 다룰 예정.
이후 RememberMeServices 를 통해서 어떤 작업을 하는데 기억하기 인증이라 한다. 보통 우리가 id 와 password를 넣고 인증을 하게 된다. 그런데 기억하기란 어떤 체크박스에 표시된 다음 인증이 성공하게 되면 세션이 만료되더라도 기억하기가 체크되기 때문에 자동적으로 id 와 password를 사용하지 않아도 그냥 로그인이 된다. 인증에 성공했기에 기억하기 인증에 체크해 인증을 수행했는지 안했는지를 체크하기에 이런 과정이 필요하다. 따라서 RememberMeService 쪽 loginSuccess 를 호출해 만약 기억하기 인증에 체크 된 경우, 활성화된 경우 그 처리를 따로 해줘야 한다.