인프런/스프링 시큐리티 완전 정복 [6.x 개정판]

3) 초기화 과정이해 - DelegatingFilterProxy / FilterChainProxy , 사용자 정의 보안 설정하기

backend dev 2024. 10. 5.

Filter

• 서블릿 필터는 웹 애플리케이션에서 클라이언트의 요청과 서버의 응답을 가공하거나 검사하는데 사용되는 구성 요소이다 [ 클라이언트의 요청 -> ServletRequest [ HttpServletRequest ] , 서버의 응답 -> ServletResponse [ HttpServletResponse] ]

 

 

• 서블릿 필터는 클라이언트의 요청이 서블릿에 도달하기 전이나 서블릿이 응답을 클라이언트에게 보내기 전에 특정 작업을 수행할 수 있다

 

• 서블릿 필터는 서블릿 컨테이너(WAS)에서 생성되고 실행되고 종료된다

3) 초기화 과정이해 - DelegatingFilterProxy / FilterChainProxy , 사용자 정의 보안 설정하기 - Filter

 

 

DelegatingFilterProxy

 

DelegatingFilterProxy는 스프링에서 사용되는 특별한 서블릿 필터로,

서블릿 컨테이너와 스프링 애플리케이션 컨텍스트 간의 연결고리 역할을 하는 필터이다

 

DelegatingFilterProxy는 서블릿 필터의 기능을 수행하는 동시에

스프링의 의존성 주입 및 빈 관리 기능과 연동되도록 설계된 필터라 할 수 있다

 

DelegatingFilterProxy는 “springSecurityFilterChain” 이름으로 생성된 빈을

ApplicationContext에서 찾아 요청을 위임한다

 

• 실제 보안 처리를 수행하지 않는다

 

3) 초기화 과정이해 - DelegatingFilterProxy / FilterChainProxy , 사용자 정의 보안 설정하기 -  DelegatingFilterProxy

필터는 스프링기술이 아니기때문에 실제로는 스프링 기술(DI, AOP등)을 사용할 수 없다.

스프링 기술을 사용하기 위해서 나온것이 DelegatingFilterProxy이다. 해당 필터에 접근하면 해당 필터가

Spring IOC Container(스프링 컨테이너)에서 springSecurityFilterChain이라는 빈을 찾고 client request의 처리를 위임한다.

해당 springSecurityFilterChain빈은 필터를 구현한 빈이여야한다.

 

FilterChainProxy

springSecurityFilterChain의 이름으로 생성되는 필터 빈으로서

DelegatingFilterProxy으로 부터 요청을 위임 받고 보안 처리 역할을 한다

 

• 내부적으로 하나 이상의 SecurityFilterChain 객체들을 가지고 있으며

요청 URL 정보를 기준으로 적절한 SecurityFilterChain 을 선택하여 필터들을 호출한다

 

HttpSecurity를 통해 API 추가 시 관련 필터들이 추가된다

 

• 사용자의 요청을 필터 순서대로 호출함으로 보안 기능을 동작시키고

필요 시 직접 필터를 생성해서 기존의 필터 전.후로 추가 가능하다

3) 초기화 과정이해 - DelegatingFilterProxy / FilterChainProxy , 사용자 정의 보안 설정하기 -  FilterChainProxy

 

 

3) 초기화 과정이해 - DelegatingFilterProxy / FilterChainProxy , 사용자 정의 보안 설정하기 -  FilterChainProxy
SecurityFilterChain으로 부터 가져온 필터 목록들을 FilterChainProxy가 처리한다.

 

 

사용자 정의 보안 설정하기

 

• 한 개 이상의 SecurityFilteChain 타입의 빈을 정의한 후 인증 API 및 인가 API 를 설정한다

 

3) 초기화 과정이해 - DelegatingFilterProxy / FilterChainProxy , 사용자 정의 보안 설정하기 -  사용자 정의 보안 설정하기
진행할 보안 설정 정리그림

 

 

@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();
    }
}

 

 

• @EnableWebSecurity 을 클래스에 정의한다

 

• 모든 설정 코드는 람다 형식으로 작성해야 한다 (스프링 시큐리티 7 버전부터는 람다 형식만 지원 할 예정)

 

• SecurityFilterChain 을 빈으로 정의하게 되면 자동설정에 의한 SecurityFilterChain 빈은 생성되지 않는다

 

 

@EnableWebSecurity: Spring Security를 활성화합니다. 이 애노테이션은 웹 보안 설정을 가능하게 합니다.

 

@Configuration: 이 클래스가 Spring의 설정 클래스임을 나타냅니다. Bean 정의를 포함할 수 있습니다.

 

 

 

@Bean: 이 메서드가 Spring 컨테이너에 의해 관리되는 Bean을 생성함을 나타냅니다.

 

SecurityFilterChain: Spring Security의 필터 체인을 구성합니다.

 

HttpSecurity http: Spring Security의 설정을 커스터마이즈할 수 있는 객체입니다.

 

 

 

  • authorizeHttpRequests(): HTTP 요청에 대한 인증/인가 규칙을 설정합니다.
  • auth -> auth.anyRequest().authenticated(): 모든 요청(anyRequest())에 대해 인증(authenticated())을 요구합니다.
  • formLogin(Customizer.withDefaults()): 기본 로그인 폼을 사용하도록 설정합니다.

 

 

위와 같이 직접 SecurityFilterChain 빈 등록을 해주면 

3) 초기화 과정이해 - DelegatingFilterProxy / FilterChainProxy , 사용자 정의 보안 설정하기 -  사용자 정의 보안 설정하기

해당 스프링의 기본코드는 동작하지않는다. @ConditionalOnDefaultWebSecurity의 조건을 타고 들어가면

3) 초기화 과정이해 - DelegatingFilterProxy / FilterChainProxy , 사용자 정의 보안 설정하기 -  사용자 정의 보안 설정하기

해당 조건을 만족하지 못하기 때문이다.

 

 

사용자 추가 설정 방법

방법 1. application.properties 혹은 application.yml 파일에 설정한다

 

application.yml

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

 

 

방법 2.  자바 설정 클래스에 직접 정의한다.

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

 

InMemoryUserDetailsManager: 메모리 내에서 사용자 정보를 관리하는 UserDetailsService 구현체입니다.

 

 

  • User.withUsername("user"): "user"라는 사용자명으로 UserDetails 객체 생성을 시작합니다.
  • .password("{noop}1234"): 비밀번호를 설정합니다. {noop}은 비밀번호 인코딩을 하지 않음을 의미합니다 (No Operation). 실제 운영 환경에서는 반드시 암호화해야 합니다.
  • .authorities("ROLE_USER"): 사용자에게 "ROLE_USER" 권한을 부여합니다.
  • .build(): UserDetails 객체를 생성합니다.
@Bean
public InMemoryUserDetailsManager inMemoryUserDetailsManager() {
    UserDetails user = User.withUsername("user")
            .password("{noop}1234")
            .authorities("ROLE_USER")
            .build();
    UserDetails user2 = User.withUsername("user2")
            .password("{noop}1234")
            .authorities("ROLE_USER")
            .build();
    UserDetails user3 = User.withUsername("user3")
            .password("{noop}1234")
            .authorities("ROLE_USER")
            .build();
    return new InMemoryUserDetailsManager(user);
}

다음과 같이 여러 유저도 생성 가능하다.

 

 

application.yml 설정과 해당 자바 config 설정과 중복이라면 config 설정이 우선적용된다.

 

 

현재 SecurityConfig 코드

@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();
    }

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

3) 초기화 과정이해 - DelegatingFilterProxy / FilterChainProxy , 사용자 정의 보안 설정하기 -  사용자 정의 보안 설정하기  - undefined -  사용자 추가 설정 방법
설정한 비밀번호 1234로 잘 로그인 된다.

 

 

댓글