"HTTP 요청이 Filter Chain을 통과해 인증·인가되는 전체 여정"
"@PreAuthorize를 쓰는 것과, FilterChainProxy가 15개 Filter를 어떤 순서로 거쳐 인증을 결정하는지 아는 것은 다르다"
FilterChainProxy.doFilter() 한 줄씩 분석부터 AuthenticationManager → ProviderManager → UserDetailsService 전체 체인,
JWT 토큰이 SecurityContext에 저장되는 과정, OAuth2 Authorization Code Flow의 모든 단계까지
왜 이렇게 설계됐는가 라는 질문으로 Spring Security 내부를 끝까지 파헤칩니다
Spring Security에 관한 자료는 넘쳐납니다. 하지만 대부분은 "어떻게 설정하나" 에서 멈춥니다.
| 일반 자료 | 이 레포 |
|---|---|
"@PreAuthorize("hasRole('ADMIN')")를 붙이면 권한 검사가 됩니다" |
FilterSecurityInterceptor가 AccessDecisionManager를 통해 GrantedAuthority 목록과 ConfigAttribute를 비교하는 Voter 체인 전 과정 |
"JWT 필터를 만들어 Security Config에 등록하세요" |
UsernamePasswordAuthenticationFilter 앞에 커스텀 JwtAuthenticationFilter를 추가했을 때 SecurityContextHolder에 Authentication이 저장되는 정확한 시점과 ExceptionTranslationFilter가 그 뒤를 받는 방식 |
"UserDetailsService를 구현하면 됩니다" |
DaoAuthenticationProvider가 UserDetailsService.loadUserByUsername()을 호출한 뒤 PasswordEncoder.matches()로 검증하고 UsernamePasswordAuthenticationToken을 생성해 SecurityContext에 저장하는 내부 코드 |
"OAuth2 로그인은 oauth2Login()으로 설정하세요" |
OAuth2LoginAuthenticationFilter가 Authorization Code를 받아 Token Endpoint를 호출하고 OAuth2User를 SecurityContext에 저장하기까지의 OAuth2AuthorizationCodeAuthenticationProvider 전 과정 |
"CSRF 토큰을 헤더에 담아야 합니다" |
CsrfFilter가 CsrfTokenRepository에서 토큰을 로드하고 X-CSRF-TOKEN 헤더와 비교하는 시점, SameSite 쿠키 정책과의 관계 |
| 이론 나열 | 실행 가능한 코드 + Spring Security 소스코드 직접 추적 + Postman/curl 인증 실험 + @WithMockUser 검증 |
각 챕터의 첫 문서부터 바로 학습을 시작하세요!
💡 각 섹션을 클릭하면 상세 문서 목록이 펼쳐집니다
핵심 질문: HTTP 요청이 들어왔을 때
FilterChainProxy는 15개 Filter를 정확히 어떤 순서로 실행하는가?
DelegatingFilterProxy부터 SecurityContext 생명주기까지 완전 분해 (7개 문서)
| 문서 | 다루는 내용 |
|---|---|
| 01. DelegatingFilterProxy와 FilterChainProxy 관계 | Servlet Container가 관리하는 DelegatingFilterProxy와 Spring이 관리하는 FilterChainProxy의 책임 분리, springSecurityFilterChain Bean이 등록되는 시점 |
| 02. SecurityFilterChain 구성과 우선순위 | 여러 SecurityFilterChain이 등록될 때 RequestMatcher로 체인을 선택하는 과정, @Order와 securityMatcher()의 상호작용 |
| 03. Security Filter 15개 완전 정복 | DisableEncodeUrlFilter부터 FilterSecurityInterceptor까지 모든 Filter의 실행 순서·역할·건너뛸 수 있는 조건, FilterOrderRegistration에서 순서를 결정하는 방식 |
| 04. SecurityContext & SecurityContextHolder | ThreadLocal 기반 SecurityContextHolder가 요청 스레드에 Authentication을 저장하고 정리하는 생명주기, MODE_INHERITABLETHREADLOCAL 전략과 비동기 환경 함정 |
| 05. Authentication 객체 구조 | Principal, Credentials, Authorities의 역할 분리, UsernamePasswordAuthenticationToken이 인증 전·후에 다른 필드를 갖는 이유, isAuthenticated() 플래그 의미 |
| 06. GrantedAuthority vs Role 차이 | ROLE_ 접두사 규칙의 기원, hasRole()과 hasAuthority()가 내부적으로 다르게 처리되는 방식, RoleHierarchy로 계층적 권한을 설정하는 메커니즘 |
| 07. SecurityContextPersistenceFilter 동작 | 요청 시작 시 HttpSession에서 SecurityContext를 복원하고 응답 후 저장하는 흐름, SecurityContextRepository의 역할, Stateless JWT 환경에서 이 Filter를 비활성화해야 하는 이유 |
핵심 질문: 폼 로그인 요청이 들어왔을 때
AuthenticationManager는 어떤 경로로 사용자를 인증하는가?
AuthenticationManager부터 Custom Provider 작성까지 (7개 문서)
| 문서 | 다루는 내용 |
|---|---|
| 01. AuthenticationManager vs ProviderManager 차이 | AuthenticationManager 인터페이스와 ProviderManager 구현체의 관계, 부모 ProviderManager로 위임하는 계층 구조, 전역 vs 로컬 AuthenticationManager 분리 전략 |
| 02. AuthenticationProvider 체인 동작 | ProviderManager가 등록된 Provider를 순서대로 supports()로 확인하는 과정, DaoAuthenticationProvider·AnonymousAuthenticationProvider 등 기본 Provider 목록 |
| 03. UserDetailsService 구현과 커스터마이징 | UserDetailsService.loadUserByUsername()의 계약, UserDetails 인터페이스의 각 필드(isAccountNonExpired, isEnabled 등)가 인증 흐름에 미치는 영향, 캐싱 전략 |
| 04. PasswordEncoder 종류와 선택 | BCryptPasswordEncoder·Argon2PasswordEncoder·SCryptPasswordEncoder 비교, DelegatingPasswordEncoder로 여러 인코더를 혼용하는 마이그레이션 전략, 인코딩 업그레이드 |
| 05. UsernamePasswordAuthenticationFilter 분석 | 폼 로그인 요청이 들어올 때 attemptAuthentication() → successfulAuthentication() / unsuccessfulAuthentication() 흐름, AuthenticationSuccessHandler가 호출되는 정확한 시점 |
| 06. Remember-Me 인증 메커니즘 | 토큰 기반(TokenBasedRememberMeServices)과 영속 토큰 기반(PersistentTokenBasedRememberMeServices) 전략 비교, RememberMeAuthenticationFilter 실행 조건 |
| 07. Custom Authentication Provider 작성 | AuthenticationProvider 구현으로 SMS OTP·API Key 인증 추가, supports() 메서드로 처리 가능한 토큰 타입을 선언하는 방식, AuthenticationManagerBuilder에 등록하는 방법 |
핵심 질문:
@PreAuthorize가 붙은 메서드는 어떻게 AOP Proxy를 통해 권한 검사를 수행하는가?
@PreAuthorize 동작 원리부터 Custom Authorization Logic까지 (6개 문서)
| 문서 | 다루는 내용 |
|---|---|
| 01. @PreAuthorize vs @Secured vs @RolesAllowed | 세 어노테이션의 SpEL 지원 여부·처리 클래스 차이, @EnableMethodSecurity와 @EnableGlobalMethodSecurity(deprecated) 전환 시 달라지는 동작 |
| 02. Method Security 동작 원리 (AOP Proxy) | AuthorizationManagerBeforeMethodInterceptor가 AOP Proxy를 통해 메서드 호출 전에 인터셉트하는 과정, MethodSecurityExpressionHandler가 SpEL 컨텍스트를 초기화하는 방식 |
| 03. FilterSecurityInterceptor 내부 구조 | URL 기반 접근 제어를 처리하는 FilterSecurityInterceptor가 SecurityMetadataSource에서 ConfigAttribute를 로드하고 AccessDecisionManager를 호출하는 전 과정 |
| 04. AccessDecisionManager와 Voter 체인 | AffirmativeBased·ConsensusBased·UnanimousBased 전략 비교, RoleVoter·WebExpressionVoter·AuthenticatedVoter가 각각 ACCESS_GRANTED를 반환하는 조건 |
| 05. SpEL을 활용한 복잡한 권한 검사 | @PreAuthorize("@permissionEvaluator.check(#id, authentication)") 패턴, PermissionEvaluator 커스터마이징으로 도메인 객체 기반 권한 검사 구현 |
| 06. Custom Authorization Logic | AuthorizationManager<MethodInvocation> 구현으로 어노테이션 없이 동적 권한 검사, SecurityContextHolder 없이 AuthorizationDecision을 반환하는 함수형 스타일 |
핵심 질문: Session Fixation 공격이란 무엇이며, Spring Security는 이를 어떻게 자동으로 방어하는가?
Session 보안 공격 방어부터 CSRF Protection까지 (6개 문서)
| 문서 | 다루는 내용 |
|---|---|
| 01. Session Fixation 공격과 방어 | 공격자가 미리 발급한 Session ID를 피해자에게 심는 공격 메커니즘, Spring Security가 인증 성공 후 changeSessionId() 또는 새 세션을 생성해 방어하는 정확한 시점 |
| 02. Concurrent Session Control (동시 로그인 제한) | maximumSessions(1) 설정 시 SessionAuthenticationStrategy가 기존 세션을 만료시키는 방식, ConcurrentSessionFilter가 만료된 세션 요청을 처리하는 흐름 |
| 03. Session Timeout 처리 | server.servlet.session.timeout 설정과 SessionManagementFilter의 관계, 세션 만료 후 InvalidSessionStrategy가 호출되는 조건, InvalidSessionUrl 설정 |
| 04. SessionRegistry 활용 | SessionRegistry로 현재 로그인한 사용자 목록 조회, 관리자가 특정 사용자의 세션을 강제 종료하는 구현, SessionInformation.expireNow()의 동작 방식 |
| 05. Stateless Session (JWT 환경) | SessionCreationPolicy.STATELESS 설정이 SecurityContextRepository와 SessionManagementFilter에 미치는 영향, 세션 없이 매 요청마다 SecurityContext를 재구성하는 과정 |
| 06. CSRF Protection 메커니즘 | CsrfFilter가 동기화 토큰 패턴으로 요청 위조를 방어하는 원리, CookieCsrfTokenRepository vs HttpSessionCsrfTokenRepository 차이, REST API에서 CSRF를 비활성화해도 안전한 조건 |
핵심 질문: Custom JWT Filter는 어떻게 토큰을 검증하고
SecurityContext에Authentication을 저장하는가?
JWT 구조 분석부터 Refresh Token Rotation까지 (7개 문서)
| 문서 | 다루는 내용 |
|---|---|
| 01. JWT 구조 완전 분석 (Header, Payload, Signature) | Base64URL 인코딩된 세 파트의 역할, alg·typ 헤더 필드가 검증 알고리즘 선택에 미치는 영향, iss·sub·exp·iat 표준 클레임의 의미와 검증 순서 |
| 02. Custom JWT Authentication Filter 작성 | OncePerRequestFilter를 상속해 Authorization: Bearer 헤더를 추출하는 구현, UsernamePasswordAuthenticationFilter 앞에 배치해야 하는 이유, shouldNotFilter() 패턴 |
| 03. JWT Token 발급 과정 (JwtTokenProvider) | io.jsonwebtoken 라이브러리로 토큰을 서명하는 과정, secretKey 관리 전략 (환경 변수·@Value), Claims에 userId·roles 커스텀 클레임을 추가하는 방법 |
| 04. JWT Token 검증과 SecurityContext 저장 | JwtParser.parseClaimsJws()가 서명·만료 시간을 검증하는 내부 과정, 검증 성공 후 Authentication 객체를 생성해 SecurityContextHolder에 저장하는 정확한 코드 경로 |
| 05. Refresh Token 전략 (RTR — Refresh Token Rotation) | Access Token 만료 시 Refresh Token으로 재발급하는 흐름, RTR 전략에서 이전 Refresh Token을 무효화해 탈취 감지하는 방법, Redis 기반 Refresh Token 저장소 구현 |
| 06. Claims 추출과 사용 | Filter 이후 Controller에서 @AuthenticationPrincipal로 커스텀 UserDetails를 주입받는 패턴, JwtAuthenticationToken.getPrincipal()에서 Claims를 꺼내 사용하는 방법 |
| 07. JWT Token 만료 및 갱신 처리 | ExpiredJwtException이 Filter에서 발생했을 때 ExceptionTranslationFilter를 거치지 않고 직접 401 응답을 보내야 하는 이유, 만료 5분 전 Silent Refresh 클라이언트 전략 |
핵심 질문: "카카오로 로그인" 버튼을 눌렀을 때
OAuth2LoginAuthenticationFilter는 내부적으로 어떤 일을 하는가?
OAuth2 Grant Type 분석부터 Resource Server 구현까지 (7개 문서)
| 문서 | 다루는 내용 |
|---|---|
| 01. OAuth2 4가지 Grant Type | Authorization Code·Implicit·Resource Owner Password·Client Credentials 각 Grant Type의 사용 시나리오, PKCE 확장이 Authorization Code Flow를 강화하는 방법 |
| 02. Authorization Code Flow 완전 분석 | /oauth2/authorization/{registrationId} 요청부터 Authorization Code 수신, Token Endpoint 호출, 사용자 정보 로드까지의 10단계 전 과정, state 파라미터가 CSRF를 방지하는 방식 |
| 03. OAuth2LoginAuthenticationFilter 동작 | OAuth2AuthorizationCodeAuthenticationProvider가 Authorization Code를 Access Token으로 교환하는 과정, OAuth2UserService를 호출해 OAuth2User를 로드하는 흐름 |
| 04. ClientRegistration과 InMemoryClientRegistrationRepository | ClientRegistration의 각 필드(clientId, redirectUri, scopes, authorizationGrantType)가 실제 HTTP 요청에서 어떻게 사용되는가, Google·Kakao 설정 비교 |
| 05. OAuth2AuthorizedClient 관리 | OAuth2AuthorizedClientRepository가 Access Token을 세션에 저장하는 방식, @RegisteredOAuth2AuthorizedClient로 Controller에서 토큰을 주입받는 패턴, 토큰 자동 갱신 |
| 06. Custom OAuth2UserService 작성 | DefaultOAuth2UserService를 확장해 소셜 계정을 DB 사용자와 연결하는 구현, 첫 로그인 시 회원가입 처리, OAuth2User와 UserDetails를 통합하는 패턴 |
| 07. JWT Bearer Token Resource Server | @EnableResourceServer(deprecated) 대신 oauth2ResourceServer(jwt()) DSL 설정, JwtDecoder가 JWK Set URI에서 공개키를 가져와 서명을 검증하는 과정, scope 기반 권한 매핑 |
핵심 질문: 실무에서 자주 마주치는 CORS, Security Headers, 멀티 테넌시 보안 이슈를 어떻게 올바르게 구성하는가?
CORS 설정부터 Multi-tenancy Security까지 (5개 문서)
| 문서 | 다루는 내용 |
|---|---|
| 01. CORS Configuration (CorsFilter vs @CrossOrigin) | CorsFilter와 @CrossOrigin이 처리되는 필터 체인 위치 차이, Preflight 요청(OPTIONS)이 인증 필터를 통과해야 하는 이유, CorsConfigurationSource 빈 등록 방식 |
| 02. Security Headers (CSP, HSTS, X-Frame-Options) | HeadersConfigurer가 자동으로 추가하는 헤더 목록, Content-Security-Policy로 XSS를 방어하는 디렉티브 구성, HSTS max-age와 includeSubDomains 설정이 적용되는 조건 |
| 03. Security Events & Listeners | AuthenticationSuccessEvent·AuthenticationFailureBadCredentialsEvent·AuthorizationDeniedEvent를 ApplicationListener로 처리하는 패턴, 로그인 실패 횟수 제한 구현 |
| 04. Method Security with SpEL 고급 활용 | @PostFilter·@PreFilter로 컬렉션 반환값·파라미터를 필터링하는 방식, returnObject·filterObject 내장 변수, 커스텀 SecurityExpressionRoot로 도메인 특화 SpEL 함수 추가 |
| 05. Multi-tenancy Security 전략 | 테넌트별 SecurityFilterChain 분리 전략, TenantContextHolder와 SecurityContextHolder 연계, Row-Level Security와 @PreAuthorize를 결합한 데이터 격리 패턴 |
🟢 "Spring Security가 마법처럼 느껴진다" — 핵심 흐름 파악 (1주)
Day 1 Ch1-01 DelegatingFilterProxy와 FilterChainProxy 관계
Day 2 Ch1-03 Security Filter 15개 완전 정복
Day 3 Ch1-04 SecurityContext & SecurityContextHolder ← 핵심
Day 4 Ch2-01 AuthenticationManager vs ProviderManager
Day 5 Ch2-03 UserDetailsService 구현과 커스터마이징
Day 6 Ch3-01 @PreAuthorize vs @Secured vs @RolesAllowed
Day 7 Ch4-06 CSRF Protection 메커니즘
🔵 "JWT 인증을 구현했지만 원리를 모른다" — JWT 완전 정복 (1주)
Day 1 Ch1-04 SecurityContext & SecurityContextHolder
Day 2 Ch1-07 SecurityContextPersistenceFilter 동작
Day 3 Ch4-05 Stateless Session (JWT 환경)
Day 4 Ch5-01 JWT 구조 완전 분석
Day 5 Ch5-02 Custom JWT Authentication Filter 작성
Day 6 Ch5-04 JWT Token 검증과 SecurityContext 저장
Day 7 Ch5-05 Refresh Token 전략 (RTR)
🟣 "OAuth2 Authorization Code Flow를 설명하지 못한다" — OAuth2 정복 (1주)
Day 1 Ch6-01 OAuth2 4가지 Grant Type
Day 2 Ch6-02 Authorization Code Flow 완전 분석 ← 핵심
Day 3 Ch6-03 OAuth2LoginAuthenticationFilter 동작
Day 4 Ch6-04 ClientRegistration 구성
Day 5 Ch6-05 OAuth2AuthorizedClient 관리
Day 6 Ch6-06 Custom OAuth2UserService 작성
Day 7 Ch6-07 JWT Bearer Token Resource Server
🔴 "Spring Security 소스코드를 직접 읽고 내부를 완전히 이해하고 싶다" — 전체 정복 (7주)
1주차 Chapter 1 전체 — Security Architecture 완전 분해
→ FilterChainProxy.doFilterInternal()에 브레이크포인트를 걸고 15개 Filter 스택 트레이스 확인
2주차 Chapter 2 전체 — Authentication Process 내부
→ DaoAuthenticationProvider.retrieveUser()에서 UserDetailsService 호출 시점 직접 추적
3주차 Chapter 3 전체 — Authorization & Method Security
→ @PreAuthorize가 붙은 메서드 호출 시 AOP Proxy가 개입하는 지점 디버거로 확인
4주차 Chapter 4 전체 — Session Management
→ SessionFixationProtectionStrategy.onAuthentication() 소스 직접 읽기
5주차 Chapter 5 전체 — JWT Authentication
→ JwtAuthenticationFilter에서 SecurityContext에 저장되는 과정을 curl 실험으로 검증
6주차 Chapter 6 전체 — OAuth2 & OpenID Connect
→ OAuth2LoginAuthenticationFilter 소스로 Authorization Code → Access Token 교환 과정 추적
7주차 Chapter 7 전체 — Advanced Topics
→ CorsFilter와 @CrossOrigin이 동시에 설정됐을 때 충돌 시나리오 MockMvc로 재현
모든 문서는 동일한 구조로 작성됩니다.
| 섹션 | 설명 |
|---|---|
| 🎯 핵심 질문 | 이 문서를 읽고 나면 답할 수 있는 질문 |
| 🔍 왜 이 보안 메커니즘이 필요한가 | 공격 시나리오와 보안 설계 배경 |
| 😱 흔한 보안 실수 | Before — 취약한 코드와 그 결과 |
| ✨ 올바른 보안 구현 | After — 안전한 코드와 원리 설명 |
| 🔬 내부 동작 원리 | Spring Security 소스코드 직접 추적 + ASCII 구조도 |
| 💻 실험으로 확인하기 | Postman/curl + @WithMockUser + 디버거 브레이크포인트 |
| 🔒 보안 체크리스트 | 이 메커니즘을 도입할 때 반드시 확인할 항목 |
| ⚖️ 트레이드오프 | 이 설계의 장단점, 언제 다른 방법을 택할 것인가 |
| 📌 핵심 정리 | 한 화면 요약 |
| 🤔 생각해볼 문제 | 개념을 더 깊이 이해하기 위한 질문 + 해설 |
이 레포의 모든 챕터는 아래 Filter 실행 흐름을 완전히 이해하는 것을 목표로 합니다.
// FilterChainProxy.doFilterInternal() — 실행되는 Filter 목록 (순서)
//
// ① Ch1-07 SecurityContextHolderFilter HTTP Session에서 SecurityContext 복원
// ② Ch7-01 CorsFilter CORS Preflight 처리 (순서 700)
// Ch4-06 CsrfFilter CSRF 토큰 검증 (순서 800)
// ③ Ch2-05 UsernamePasswordAuthenticationFilter 폼 로그인 처리
// JwtAuthenticationFilter (Custom) JWT 검증 → SecurityContext 저장 ← Ch5
// BasicAuthenticationFilter Basic Auth 처리
// BearerTokenAuthenticationFilter OAuth2 Resource Server ← Ch6-07
// ④ RequestCacheAwareFilter 이전 요청 복원
// SecurityContextHolderAwareRequestFilter
// ⑤ AnonymousAuthenticationFilter 인증 없는 요청에 익명 Authentication 부여
// ⑥ Ch4-01 SessionManagementFilter 세션 고정 방어, 동시 접속 제어
// ⑦ ExceptionTranslationFilter AuthenticationException → 401 (로그인 리다이렉트)
// AccessDeniedException → 익명 사용자: 401 / 인증된 사용자: 403
// ⑧ Ch3-03 AuthorizationFilter URL 기반 권한 검사 (최종 관문)
//
//
// 인증 성공 후 흐름:
// JwtAuthenticationFilter
// → JwtTokenProvider.validateToken() 서명 + 만료 시간 검증
// → JwtTokenProvider.getAuthentication() Claims → UsernamePasswordAuthenticationToken
// → SecurityContextHolder.setContext() ThreadLocal에 저장
// → FilterChain.doFilter() 다음 Filter로 진행
// → DispatcherServlet → Controller| 레포 | 주요 내용 | 연관 챕터 |
|---|---|---|
| spring-core-deep-dive | IoC 컨테이너, DI, AOP, Bean 생명주기, Proxy | Ch3(Method Security AOP Proxy), Ch7(Multi-tenancy) |
| spring-mvc-deep-dive | DispatcherServlet, Filter vs Interceptor, ArgumentResolver | Ch1(DelegatingFilterProxy — Servlet Filter 이해 필수), Ch5(JWT Custom Filter 배치) |
| spring-boot-internals | Auto-configuration, SecurityAutoConfiguration |
Ch1(SecurityFilterChain 자동 등록 과정) |
| spring-data-transaction | JPA, 트랜잭션 | Ch2(UserDetailsService DB 조회), Ch5(Refresh Token Redis 저장) |
💡 선행 필수: Spring Core의 AOP / Proxy 개념(Ch3 Method Security), Spring MVC의 Servlet Filter 개념(Ch1 FilterChain)이 반드시 필요합니다.
나머지 챕터는 독립적으로 학습 가능합니다.
각 챕터가 방어하는 OWASP 위협 목록입니다.
| OWASP | 위협 | 관련 챕터 |
|---|---|---|
| A01 | Broken Access Control | Ch3 Authorization, Ch7 Multi-tenancy |
| A02 | Cryptographic Failures | Ch5 JWT 서명, Ch2 PasswordEncoder |
| A03 | Injection | Ch3 SpEL 안전한 사용 |
| A05 | Security Misconfiguration | Ch1 Filter 순서, Ch7 Security Headers |
| A07 | Identification and Authentication Failures | Ch2 Authentication, Ch4 Session |
| A08 | Software and Data Integrity Failures | Ch5 JWT 검증, Ch6 OAuth2 state |
| A09 | Security Logging and Monitoring Failures | Ch7 Security Events |
A04(Insecure Design), A06(Vulnerable Components), A10(SSRF)은 이 레포의 범위 밖입니다.
- Spring Security Reference Documentation
- Spring Security Source Code (GitHub)
- OWASP Top Ten
- RFC 7519 — JSON Web Token (JWT)
- RFC 6749 — The OAuth 2.0 Authorization Framework
- jwt.io — JWT Debugger
- Baeldung Spring Security Guides
⭐️ 도움이 되셨다면 Star를 눌러주세요!
Made with ❤️ by Dev Book Lab
"@PreAuthorize를 쓰는 것과, FilterChainProxy가 15개 Filter를 어떤 순서로 거쳐 인증을 결정하는지 아는 것은 다르다"