- 스프링 시큐리티는 FilterChain 기반으로 동작한다.
- 스프링 시큐리티의 인증은 인증을 담당하는 Filter에 의해 처리된다.
- 가장 일반적인 인증 과정인 UsernamePassword 인증 과정의 흐름을 이해해보자.

Authentication을 담당하는 주요 인터페이스는 아래와 같다.
각 클래스(인터페이스)의 입장에서 일어나는 일을 순차적으로 기술
UsernamePasswordAuthenticationFilter
- 인증 필터 (Filter의 구현체)
- doFilter 호출
doFilter
메소드는 부모 추상클래스에 구현되어 있음
doFilter(req, resp, chain){ if(!인증_요청_임?(req,resp)){ 다음_필터로_고고(chain) }else{ 인증된_인증객체 = 인증시도(req,resp); if(인증된_인증객체== null) return; // FilterChainProxy로 돌아가서 다음 필더 ㄱㄱ 세션전략_적용_로직(인증된_인증객체, req, resp); if(세션에서_이미_로그인?){ //성공_로직_적용필요없음 다음_필터로_고고(chain) } 성공핸들러.성공로직(req, resp, chain, 인증된_인증객체) 예외_터졌음? -> 실패_핸들러.실패로직(req,resp,ex); return; // FilterChainProxy로 돌아가서 다음 필더 ㄱㄱ }
AbstractAuthenticationProcessingFilter.doFilter
슈도 코드- 여기서 chain은 FilterChainProxy의 inner class인 VirtualFilterChain 이므로 깡
return
이나다음_필터로_고고(chain)
이나 사실상 같음
인증시도(req,resp)
의 내부
-
AuthenticationManager
에게 -
Authentication
- 인증안된 인증객체 전달 Authentication
- 인증된 인증객체 받아옴
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); this.setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest)
UsernamePasswordAuthenticationFilter.attemptAuthentication
메소드 中ProviderManager
- 인증 관리자 (AuthenticationManager 의 구현체)
- 자신이가진 AuthenticationProvider 중에 해당 인증객체를 지원하는 provider를 찾아 인증 안된 인증객체를 전달, 인증 로직을 위임
authentication(인증객체 인증_안된_인증객체){ for(인증제공자 : 인증제공자_목록){ if(인증제공자.지원(인증객체.class)){ 결과 =인증_제공자.인증(인증_안된_인증객체) } } if(결과 == null) { 부모.authenticate(인증_안된_인증객체) } 대충_예외처리 대충_보안처리 대충_이벤트처리 return 결과 (= 인증된 인증 객체) }
DaoAuthenticationProvider
- 인증 제공자 (AuthenticationProvider 의 구현체)
authenticate
호출
- authenticate 메소드는 부모 추상클래스에 구현되어있음
authenticate(인증객체 인증_안된_인증객체){ username = username뽑아내(인증_안된_인증객체) try{ user = retrieveUser(username, 인증안된 인증객체) } catch {usernameNotFoundException e} { throw BadCredentialsException } 비밀번호_매칭_검증(user, 인증_안된_인증객체 ) 다통과 -> return 인증된_인증객체 }
AbstractUserDetailsAuthenticationProvider.authenticate
슈도 코드retrieveUser
호출
retrieveUser(사용자이름, 인증안된_인증객체){ 대충 보안처리 대충_예외처리 return userDetailsService.loadUserByUsername(username); }
DaoAuthenticationProvider.retrieveUser
슈도 코드비밀번호_매칭_검증
호출
if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) { throw new BadCredentialsException()); }
DaoAuthenticationProvider.additionalAuthenticationChecks
메소드 中UserDetailsService
혹은 UserDetailsManager
package org.springframework.security.core.userdetails; public interface UserDetailsService { UserDetails loadUserByUsername(String username) throws UsernameNotFoundException; }
- 제주껏 UserDetails 객체를 하나 생성하는 메서드를 구현하면 된다.