Spring Security Customizer

Jindolph·2024년 8월 5일

Spring Security Customizer를 사용한 설정 방법

Spring Security의 최신 버전에서는 보안 설정을 Customizer를 사용하여 구성하는 방식을 권장하고 있습니다. 이 방식은 Spring Boot 2.7 및 Spring Security 5.7부터 도입되었습니다. 아래는 Customizer를 사용한 보안 설정 예시입니다.

메서드 체이닝 방식에서 Customizer로 변경된 이유

  1. 유연성 향상: Customizer를 사용하면 보안 설정을 보다 유연하게 구성할 수 있습니다. 여러 개의 Customizer를 조합하여 재사용 가능하고 모듈화된 설정을 만들 수 있습니다. 이는 대규모 애플리케이션에서 특히 유용합니다.
  2. 코드의 가독성 및 유지보수성 향상: 메서드 체이닝 방식은 설정이 복잡해질수록 가독성이 떨어지고, 유지보수가 어려워질 수 있습니다. Customizer를 사용하면 설정을 여러 개의 클래스로 분리할 수 있어 코드의 가독성과 유지보수성이 향상됩니다.
  3. 테스트 용이성: Customizer를 사용하면 개별 설정 클래스를 독립적으로 테스트할 수 있어 테스트 코드 작성이 용이합니다. 이는 보안 설정이 제대로 작동하는지 확인하는 데 큰 도움이 됩니다.
  4. DI(의존성 주입)와의 통합: Spring의 의존성 주입과 자연스럽게 통합되어, 필요에 따라 다른 빈(bean)을 주입받아 사용할 수 있습니다. 이는 설정 클래스 간의 의존성을 관리하는 데 유리합니다.
  5. 컨벤션에 의한 구성: Customizer를 사용하면 설정의 일관성을 유지하고, Spring Security 팀이 권장하는 컨벤션에 따라 구성을 단순화할 수 있습니다.

SecurityConfig 클래스

SecurityConfig 클래스에서 보안 설정을 정의하고 필요한 Customizer를 주입합니다.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    private final CorsCustomizer corsCustomizer;
    private final AuthorizeExchangeCustomizer authorizeExchangeCustomizer;
    private final OAuth2ResourceServerCustomizer oauth2ResourceServerCustomizer;

    @Autowired
    public SecurityConfig(
            @Qualifier("corsCustomizer") CorsCustomizer corsCustomizer,
            @Qualifier("authorizeExchangeCustomizer") AuthorizeExchangeCustomizer authorizeExchangeCustomizer,
            @Qualifier("oAuth2ResourceServerCustomizer") OAuth2ResourceServerCustomizer oauth2ResourceServerCustomizer
    ) {
        this.corsCustomizer = corsCustomizer;
        this.authorizeExchangeCustomizer = authorizeExchangeCustomizer;
        this.oauth2ResourceServerCustomizer = oauth2ResourceServerCustomizer;
    }

    @Bean
    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
        http
                // CSRF 설정 (이와 같이, 간단한 설정은 람다로 가능.)
                .csrf(ServerHttpSecurity.CsrfSpec::disable)
                // CORS 설정
                .cors(corsCustomizer)
                // HTTP 보안 설정
                .authorizeExchange(authorizeExchangeCustomizer)
                // Oauth2 & JWT 인증 필터 설정
                .oauth2ResourceServer(oauth2ResourceServerCustomizer);
                
                // 아래 설정들도 필요한 경우, customizer 를 생성.
                // .formLogin()
                // .httpBasic()
                // .anonymous()
                // .authenticationManager()
                // .exceptionHandling()
                // .headers()
                // .logout()
                // .passwordManagement()
        return http.build();
    }
}

AuthorizeExchangeCustomizer 클래스

이 클래스는 ServerHttpSecurity.AuthorizeExchangeSpec을 커스터마이징합니다.
여기서 특정 URL 패턴에 대한 접근 권한을 설정할 수 있습니다. 예시로, 하나만 작성 하겠습니다.

유사한 방식으로, corsCustomizer, oauth2ResourceServerCustomizer 등을 작성 할 수 있습니다.

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity.AuthorizeExchangeSpec;
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers;
import org.springframework.web.server.handler.FilteringWebHandler;

@Configuration("authorizeExchangeCustomizer")
public class AuthorizeExchangeCustomizer implements Customizer<ServerHttpSecurity.AuthorizeExchangeSpec> {

    @Override
    public void customize(ServerHttpSecurity.AuthorizeExchangeSpec authorizeExchangeSpec) {
        authorizeExchangeSpec
                .pathMatchers(HttpMethod.GET, "/health").permitAll()
                .pathMatchers(HttpMethod.POST, "/auth/login").permitAll()
                .anyExchange().authenticated();
    }
}

참고 자료

profile
Hello World!

0개의 댓글