Java & Spring/Spring Security

01. 초기화 과정 이해

승주우에요 2026. 8. 1. 14:00
초기화 과정 이해 - Spring Security

초기화 과정 이해

Spring Security의 자동 설정과 필터 체인 초기화 구조

Spring Security는 애플리케이션이 기동될 때 자동 설정을 통해 보안 인프라를 초기화한다. 이 챕터에서는 프로젝트 구성부터 SecurityBuilder/SecurityConfigurer의 관계, HttpSecurity와 WebSecurity의 역할, 그리고 DelegatingFilterProxy와 FilterChainProxy를 통한 필터 체인 위임 구조까지 Spring Security의 초기화 전반을 다룬다.

1. 프로젝트 생성 및 자동 설정

개념

Spring Boot 3.x 기반 프로젝트에 spring-boot-starter-security 의존성을 추가하면 별도의 설정 코드 없이도 기본적인 웹 보안 기능이 자동으로 활성화된다. 자동 설정에 의해 다음과 같은 기본 보안 정책이 적용된다.

  • 모든 요청에 대해 인증 여부를 검증하며 인증이 승인되어야 자원에 접근할 수 있다
  • 인증 방식은 폼 로그인과 httpBasic 로그인을 제공한다
  • 로그인 페이지가 자동으로 생성되어 렌더링된다
  • 기본 계정 한 개가 제공된다 (username: user, password: 콘솔에 출력되는 랜덤 문자열)

이 기본 설정은 SpringBootWebSecurityConfiguration 클래스에 의해 생성된다.

핵심 코드

// SpringBootWebSecurityConfiguration 자동 설정 클래스
@Bean
@Order(SecurityProperties.BASIC_AUTH_ORDER)
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) {
    http.authorizeRequests().anyRequest().authenticated();
    http.formLogin();
    http.httpBasic();
    return http.build();
}
// build.gradle 의존성 구성
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'org.springframework.security:spring-security-test'
}
📍 브레이크포인트: SpringBootWebSecurityConfiguration#defaultSecurityFilterChain
확인할 변수: http 객체 내부의 설정 클래스 목록, 생성되는 필터 체인

2. SecurityBuilder / SecurityConfigurer

개념

SecurityBuilder는 빌더 클래스로서 웹 보안을 구성하는 빈 객체와 설정 클래스들을 생성하는 역할을 한다. 대표적인 구현체로 HttpSecurity, WebSecurity, AuthenticationManagerBuilder가 있다.

SecurityConfigurer는 HTTP 요청과 관련된 보안 처리를 담당하는 필터들을 생성하고 여러 초기화 설정에 관여한다. 대표적인 구현체로는 SecurityContextConfigurer, HttpBasicConfigurer, FormLoginConfigurer, CsrfConfigurer, ExceptionHandlingConfigurer, AnonymousConfigurer 등이 있다.

SecurityBuilderSecurityConfigurer를 참조하고 있으며, 인증 및 인가 초기화 작업은 SecurityConfigurer에 의해 진행된다.

동작 흐름

sequenceDiagram participant AC as AutoConfiguration participant SB as SecurityBuilder participant SC as SecurityConfigurer AC->>SB: build() 호출 Note over SB: ① 빌더 클래스 생성 SB->>SC: 설정 클래스 생성 Note over SC: ② SecurityConfigurer 인스턴스화 SC-->>SB: init(B builder) SC-->>SB: configure(B builder) Note over SC: ③ 초기화 작업 진행 → 필터 생성

SecurityConfigurer → Filter 매핑

flowchart LR subgraph SB["SecurityBuilder (HttpSecurity)"] direction TB B["build() 호출"] end SB --> SC subgraph SC["SecurityConfigurer 목록"] direction TB C1["FormLoginConfigurer"] C2["HttpBasicConfigurer"] C3["CsrfConfigurer"] C4["LogoutConfigurer"] C5["SecurityContextConfigurer"] C6["ExceptionHandlingConfigurer"] C7["SessionManagementConfigurer"] end SC --> FT subgraph FT["생성되는 Filter"] direction TB F1["UsernamePasswordAuthenticationFilter"] F2["BasicAuthenticationFilter"] F3["CsrfFilter"] F4["LogoutFilter"] F5["SecurityContextHolderFilter"] F6["ExceptionTranslationFilter"] F7["SessionManagementFilter"] end C1 --> F1 C2 --> F2 C3 --> F3 C4 --> F4 C5 --> F5 C6 --> F6 C7 --> F7
📍 브레이크포인트: AbstractConfiguredSecurityBuilder#doBuild()
확인할 변수: configurers 맵 — 등록된 SecurityConfigurer 목록과 각 Configurer가 생성하는 필터

3. HttpSecurity / WebSecurity

HttpSecurity

HttpSecurityConfiguration에서 HttpSecurity를 생성하고 초기화를 진행한다. HttpSecurity는 보안에 필요한 각 설정 클래스와 필터들을 생성하고 최종적으로 SecurityFilterChain 빈을 생성한다.

WebSecurity

WebSecurityConfiguration에서 WebSecurity를 생성하고 초기화를 진행한다. HttpSecurity에서 생성한 SecurityFilterChain 빈을 SecurityBuilder에 저장한다. WebSecuritybuild()를 실행하면 SecurityFilterChain을 꺼내어 FilterChainProxy 생성자에게 전달한다.

전체 빌드 흐름

flowchart TD A["HttpSecurityConfiguration"]:::config -->|생성| B["HttpSecurity"]:::builder B -->|내부 보관| C["Map<SecurityConfigurer>"]:::map C -->|"build()"| D["DefaultSecurityFilterChain"]:::chain F["WebSecurityConfiguration"]:::config -->|생성| G["WebSecurity"]:::builder D -->|전달| H["securityFilterChainBuilders"]:::map G --> H H -->|"build()"| I["FilterChainProxy"]:::proxy I -->|내부 보관| J["List<SecurityFilterChain>"]:::chain classDef config fill:#2d333b,stroke:#768390,color:#adbac7 classDef builder fill:#1c3a5f,stroke:#58a6ff,color:#ffffff classDef map fill:#2d333b,stroke:#768390,color:#adbac7 classDef chain fill:#1a3a2a,stroke:#3fb950,color:#ffffff classDef proxy fill:#3d1f5c,stroke:#bc8cff,color:#ffffff

SecurityFilterChain 인터페이스

SecurityFilterChain은 두 가지 핵심 메서드를 가진 인터페이스다.

  • boolean matches(HttpServletRequest request) — 현재 요청이 이 필터 체인에 의해 처리되어야 하는지 여부를 결정한다
  • List<Filter> getFilters() — 현재 필터 체인에 포함된 Filter 객체의 리스트를 반환한다

기본 필터 목록

HttpSecurity의 기본 설정으로 생성되는 필터 체인:

순서필터
0DisableEncodeUrlFilter
1WebAsyncManagerIntegrationFilter
2SecurityContextHolderFilter
3HeaderWriterFilter
4CorsFilter
5CsrfFilter
6LogoutFilter
7UsernamePasswordAuthenticationFilter
8DefaultLoginPageGeneratingFilter
9DefaultLogoutPageGeneratingFilter
10BasicAuthenticationFilter
11RequestCacheAwareFilter
12SecurityContextHolderAwareRequestFilter
13AnonymousAuthenticationFilter
14ExceptionTranslationFilter
15AuthorizationFilter
📍 브레이크포인트: HttpSecurity#build()DefaultSecurityFilterChain 생성 시점
확인할 변수: result 객체의 requestMatcherfilters (size = 12~16)

📍 브레이크포인트: WebSecurity#performBuild()FilterChainProxy 생성 시점
확인할 변수: filterChainProxyfilterChains 리스트와 내부 필터 목록

4. DelegatingFilterProxy / FilterChainProxy

서블릿 필터 (Filter)

서블릿 필터는 웹 애플리케이션에서 클라이언트의 요청과 서버의 응답을 가공하거나 검사하는 구성 요소다. 서블릿 컨테이너(WAS)에서 생성되고 실행되며, 요청이 서블릿에 도달하기 전이나 응답이 클라이언트에게 전달되기 전에 특정 작업을 수행할 수 있다.

public class ExampleFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 필터 초기화 시 필요한 작업 수행
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {
        // pre-processing: 요청 처리 전 작업
        chain.doFilter(request, response); // 다음 필터로 전달
        // post-processing: 응답 처리 후 작업
    }
    @Override
    public void destroy() {
        // 필터가 제거될 때 정리 작업 수행
    }
}

DelegatingFilterProxy

스프링에서 사용되는 특별한 서블릿 필터로, 서블릿 컨테이너와 스프링 애플리케이션 컨텍스트 간의 연결고리 역할을 한다. "springSecurityFilterChain" 이름으로 생성된 빈을 ApplicationContext에서 찾아 요청을 위임하며, 실제 보안 처리를 수행하지는 않는다.

FilterChainProxy

"springSecurityFilterChain" 이름으로 생성되는 필터 빈으로서, DelegatingFilterProxy로부터 요청을 위임 받아 실제 보안 처리를 수행한다. 내부적으로 하나 이상의 SecurityFilterChain 객체들을 가지고 있으며 요청 URL 정보를 기준으로 적절한 SecurityFilterChain을 선택하여 필터들을 호출한다.

전체 위임 구조

sequenceDiagram participant Client participant SC as Servlet Container participant DFP as DelegatingFilterProxy participant FCP as FilterChainProxy participant SFC as SecurityFilterChain participant Servlet Client->>SC: HTTP 요청 SC->>DFP: FilterChain 중 DelegatingFilterProxy 도달 DFP->>FCP: "springSecurityFilterChain" 빈에 위임 FCP->>SFC: URL 매칭으로 적절한 SecurityFilterChain 선택 SFC->>SFC: Filter 0 → Filter 1 → ... → Filter N 순서 실행 SFC-->>Servlet: 모든 필터 통과 시 서블릿으로 전달 Servlet-->>Client: HTTP 응답

DelegatingFilterProxy → FilterChainProxy 위임 구조

flowchart LR subgraph SERVLET["Servlet Container"] direction TB F1["Filter"]:::servlet_f DFP["DelegatingFilterProxy"]:::dfp F2["Filter"]:::servlet_f SV["Servlet"]:::servlet_f F1 --> DFP --> F2 --> SV end DFP -->|"'springSecurityFilterChain'
요청 위임"| FCP subgraph SPRING["Spring IoC Container"] direction TB FCP["FilterChainProxy"]:::fcp subgraph SFC["SecurityFilterChain"] direction TB SF0["AuthenticationFilter"]:::sec_f SF1["..."]:::sec_f SF2["AuthorizationFilter"]:::sec_f SF0 --> SF1 --> SF2 end FCP --> SFC end classDef servlet_f fill:#2d333b,stroke:#768390,color:#e6edf3 classDef dfp fill:#1c3a5f,stroke:#58a6ff,color:#ffffff,font-weight:bold classDef fcp fill:#3d1f5c,stroke:#bc8cff,color:#ffffff,font-weight:bold classDef sec_f fill:#1a3a2a,stroke:#3fb950,color:#e6edf3

FilterChainProxy의 필터 순차 실행

FilterChainProxy는 0번째 필터부터 마지막 필터까지 위에서 순서대로 호출하면서 요청을 처리한다. 마지막 인가 처리를 하는 필터(AuthorizationFilter)까지 특별한 예외나 오류가 발생하지 않으면 성공적으로 요청이 서블릿으로 넘어가게 된다.

flowchart TD subgraph VFC["FilterChainProxy$VirtualFilterChain"] direction TB P["currentPosition = 0"]:::pos F0["▶ 0 DisableEncodeUrlFilter"]:::vf F1["▶ 1 WebAsyncManagerIntegrationFilter"]:::vf F2["▶ 2 SecurityContextHolderFilter"]:::vf F3["▶ 3 HeaderWriterFilter"]:::vf F4["▶ 4 CorsFilter"]:::vf F5["▶ 5 CsrfFilter"]:::vf F6["▶ 6 LogoutFilter"]:::vf F7["▶ 7 UsernamePasswordAuthenticationFilter"]:::vf F8["▶ 8 DefaultLoginPageGeneratingFilter"]:::vf F9["▶ 9 DefaultLogoutPageGeneratingFilter"]:::vf F10["▶ 10 BasicAuthenticationFilter"]:::vf F11["▶ 11 RequestCacheAwareFilter"]:::vf F12["▶ 12 SecurityContextHolderAwareRequestFilter"]:::vf F13["▶ 13 AnonymousAuthenticationFilter"]:::vf F14["▶ 14 ExceptionTranslationFilter"]:::vf F15["▶ 15 AuthorizationFilter"]:::vf_last P --> F0 --> F1 --> F2 --> F3 --> F4 --> F5 --> F6 --> F7 --> F8 --> F9 --> F10 --> F11 --> F12 --> F13 --> F14 --> F15 end F15 -->|"통과"| SERVLET["Servlet"]:::sv classDef pos fill:#3b2300,stroke:#d29922,color:#e3b341,font-weight:bold classDef vf fill:#2d333b,stroke:#768390,color:#e6edf3 classDef vf_last fill:#1a3a2a,stroke:#3fb950,color:#e6edf3,font-weight:bold classDef sv fill:#1c3a5f,stroke:#58a6ff,color:#ffffff
📍 브레이크포인트: DelegatingFilterProxy#doFilter() — 위임 시점
확인할 변수: delegate — 실제 위임 대상 FilterChainProxy 객체

📍 브레이크포인트: FilterChainProxy$VirtualFilterChain#doFilter() — 필터 순차 실행
확인할 변수: additionalFilters (size=16), currentPosition (0→15 증가)

5. 사용자 정의 보안 설정하기

개념

기본 자동 설정 대신 사용자 정의 보안 설정을 구성하려면 SecurityFilterChain 타입의 빈을 직접 정의한다. 사용자 정의 SecurityFilterChain 빈을 등록하면 자동 설정에 의한 SecurityFilterChain 빈은 생성되지 않는다.

사용자 정의 보안 기능 구현

flowchart TD SC["SecurityConfig
@EnableWebSecurity"]:::config --> SFC["SecurityFilterChain
빈으로 정의"]:::chain SFC --> HS["HttpSecurity
의존 주입"]:::builder HS --> AUTH_API HS --> AUTHZ_API subgraph AUTH_API["인증 API"] direction TB A1["http.formLogin()"]:::api A2["http.logout()"]:::api A3["http.csrf()"]:::api A4["http.httpBasic()"]:::api A5["http.sessionManagement()"]:::api A6["http.rememberMe()"]:::api A7["http.exceptionHandling()"]:::api A8["http.addFilter()"]:::api end subgraph AUTHZ_API["인가 API"] direction TB B1["http.authorizeHttpRequests()"]:::api B2[".requestMatchers('/admin')"]:::api B3[".hasRole('USER')"]:::api B4[".permitAll()"]:::api B5[".authenticated()"]:::api B6[".denyAll()"]:::api end classDef config fill:#3d1f5c,stroke:#bc8cff,color:#ffffff,font-weight:bold classDef chain fill:#1a3a2a,stroke:#3fb950,color:#ffffff classDef builder fill:#1c3a5f,stroke:#58a6ff,color:#ffffff classDef api fill:#2d333b,stroke:#768390,color:#e6edf3

기본 구현 코드

@EnableWebSecurity
@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
            .formLogin(Customizer.withDefaults());

        return http.build();
    }
}
Spring Security 7 버전부터는 람다 형식만 지원할 예정이므로, 설정 코드는 람다 형식으로 작성하는 것이 권장된다. SecurityFilterChain을 빈으로 정의하게 되면 자동설정에 의한 SecurityFilterChain 빈은 생성되지 않는다.

사용자 추가 설정

application.yml 파일에 사용자를 설정할 수 있다.

spring:
  security:
    user:
      name: user
      password: 1111
      roles: USER

또는 자바 설정 클래스에서 InMemoryUserDetailsManager를 직접 정의할 수도 있다.

@Bean
public InMemoryUserDetailsManager inMemoryUserDetailsManager() {
    UserDetails user = User.withUsername("user")
        .password("{noop}1111")
        .authorities("ROLE_USER")
        .build();
    return new InMemoryUserDetailsManager(user);
}

정리

  • spring-boot-starter-security 의존성만으로 기본 보안 설정이 자동 적용된다
  • SecurityBuilder는 보안 객체를 생성하는 빌더이며, SecurityConfigurer가 실제 초기화 작업을 수행한다
  • HttpSecurity는 각 SecurityConfigurer를 통해 필터들을 생성하고 SecurityFilterChain을 만든다
  • WebSecurity는 SecurityFilterChain을 모아 FilterChainProxy를 생성한다
  • DelegatingFilterProxy는 서블릿 컨테이너와 스프링 컨텍스트 사이의 브릿지 역할을 하며, 실제 보안 처리는 FilterChainProxy에 위임된다
  • 사용자 정의 SecurityFilterChain 빈을 등록하면 자동 설정 빈을 대체하여 세부적인 보안 정책을 구성할 수 있다

'Java & Spring > Spring Security' 카테고리의 다른 글

06. 예외 처리  (0) 2026.08.05
05. 세션 관리  (0) 2026.08.05
04. 인증 상태 영속성  (0) 2026.08.04
03. 인증 아키텍처  (0) 2026.08.04
02. 인증 프로세스  (0) 2026.08.01