초기화 과정 이해(1/13)

dev.hyjang·2024년 5월 17일

스프링 시큐리티

목록 보기
2/6

프로젝트 생성 / 의존성 추가

프로젝트 구성

  • 기본 구성

    • Spring Boot 3.x
    • JDK 17
    • Gradle
  • 의존성 주입

    • spring-boot-starter-web
    • spring-boot-starter-security

자동 설정에 의한 보안 작동

  • 서버가 기동되면 스프링 시큐리티의 초기화 작업 및 보안 설정이 이루어짐
  • 별도의 설정이나 코드를 작성하지 않아도 기본적인 웹 보안 기능이 작동
    1) 인증여부 검증 -> 인증 승인 -> 자원 접근 가능
    2) 인증 방식: form 로그인, httpBasic 로그인
    3) 로그인 페이지 자동 생성
    4) 인증 승인 가능한 계정 1개 기본 제공
    - username: user
    - password: 랜덤 문자열
    - SecurityProperties 설정 클래스에서 생성!
		@Bean
		@Order(SecurityProperties.BASIC_AUTH_ORDER)
		SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
			http.authorizeHttpRequests((requests) -> requests.anyRequest().authenticated());
			http.formLogin(withDefaults()); //form  로그인
			http.httpBasic(withDefaults()); //httpBasic 로그인
			return http.build();
		}


SecurityBuilder / SecurityConfigurer

*이 두 가지 설정 파일만 잘 이해하고 있어도 스프링 시큐리티 초기화 작업에 대해서 파악할 수 있다.

1. 시큐리티 Builder

  • 빌더 클래스
  • 웹 보안 구성하는 빈 객체, 설정 클래스 생성
  • WebSecurity, HttpSecurity 가 있음

2. 시큐리티 Configurer

  • 여러 초기화 설정 관여
  • Http 요청과 관련된 보안처리를 담당하는 필터 생성
  • 스프링 시큐리티는 모든 인증, 인가 요청을 필터를 통해서 함
    => "필터" 기반 보안


HttpSecurity / WebSecurity

HttpSecurity

  • HttpSecurityConfiguration 에서 HttpSecurity 생성, 초기화
  • 보안에 필요한 각 설정 클래스와 필터 생성
  • SecurityFilterChain 빈 생성
    1. boolean matches(HttpServletRequest request) : 필터 체인 처리 여부 확인
    2. List getFilters() : 필터 객체 리스트 반환, (인증, 권한 부여, 로깅 등 수행)

WebSecurity

  • WebSecurityConfiguration 에서 WebSecurity 를 생성, 초기화
  • WebSecurity 는 HttpSecurity 에서 생성한 SecurityFilterChain 빈을 SecurityBuilder 에 저장
  • WebSecurity 가 build() 를 실행하면 SecurityBuilder 에서 SecurityFilterChain 을 꺼내어 FilterChainProxy 생성자에게 전달
- HttpSecurity 에서 생성한 SecurityFilterChain 빈을 SecurityBuilder 에 저장 후 빌드
- SecurityBuilder 에서 SecurityFilterChain 을 꺼내어 FilterChainProxy 생성자에게 전달


DelegatingFilterProxy / FilterChainProxy

Filter

  • 서블릿 필터는 웹 애플리케이션에서 클라이언트의 요청(HttpServletRequest)과 서버의 응답(HttpServletResponse)을 가공하거나 검사하는데 사용
  • 클라이언트의 요청이 서블릿에 도달하기 전 or 서블릿의 응답을 클라이언트에 보내기 전에 특정 작업을 수행
  • 서블릿 컨테이너(WAS)에서 생성, 실행, 종료
  • 필터는 선택사항
  • init() -> doFilter() -> destroy()

DelegatingFilterProxy

  • DelegatingFilterProxy 는 스프링에서 사용되는 특별한 서블릿 필터로, 서블릿 컨테이너와 스프링 애플리케이션 컨텍스트 간의 연결고리 역할을 하는 필터임
  • DelegatingFilterProxy 는 서블릿 필터의 기능을 수행하는 동시에 스프링의 의존성 주입 및 빈 관리 기능과 연동되도록 설계된 필터
  • DelegatingFilterProxy 는 “springSecurityFilterChain” 이름으로 생성된 빈을 ApplicationContext 에서 찾아 요청을 위임함
  • 실제 보안 처리를 수행하지 않음

  • 필터의 기능 + spring의 DI, AoP 같은 기능 처리하려고 만든 것
  • Spring IOC Container 에서 springSecurityFilterChain 빈을 찾아서 클라이언트의 요청을 위임함. 그러면 Spring Bean이 필터를 구현함

FilterChainProxy

  • springSecurityFilterChain 의 이름으로 생성되는 필터 빈으로서 DelegatingFilterProxy 으로 부터 요청을 위임 받고 보안 처리 역할을 한다
  • 내부적으로 하나 이상의 SecurityFilterChain 객체들을 가지고 있으며 요청 URL 정보를 기준으로 적절한 SecurityFilterChain 을 선택하여 필터들을 호출한다
  • HttpSecurity 를 통해 API 추가 시 관련 필터들이 추가된다
  • 사용자의 요청을 필터 순서대로 호출함으로 보안 기능을 동작시키고 필요 시 직접 필터를 생성해서 기존의 필터 전.후로 추가 가능하다



사용자 정의 보안 설정하기

직접 SecurityConfig 생성

  1. SecurityConfig 클래스 생성 후 @EnableWebSecurity 선언
  2. 설정 코드는 람다로 작성!(스프링 시큐리티 7버전 부터는 람다 형식만 지원)
  3. SecurityFilterChain 을 빈으로 정의하면 자동 설정에 의한 빈은 생성되지 않음!
@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();
    }
}

사용자 추가 설정

  1. application.yml 파일에 설정
spring:
  security:
    user:
      name: user
      password: 1111
      roles: USER
  1. 자바 설정 클래스에 직접 정의
    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails user = User.withUsername("user")
                .password("{noop}1111")
                .roles("USER").build();
        UserDetails user2 = User.withUsername("user2")
                .password("{noop}1111")
                .roles("USER").build();
        UserDetails user3 = User.withUsername("user3")
                .password("{noop}1111")
                .roles("USER").build();
        return new InMemoryUserDetailsManager(user, user2, user3);
profile
낭만감자

0개의 댓글