Spring Security 공부기록 - (2) 기존 프로젝트와 차이점

j00r6·2024년 1월 15일
0

Spring Security

목록 보기
2/3

기존 프로젝트와 차이점


학습을 진행할때 사용했던 spring initializr 에 접속해보니 기존에 사용했던 버전들이 비활성화 되있었다.

버전을 낮추어 기존 개발방식대로 진행할수 있었지만
우리는 신버전으로 새로운 개발을 진행해보기로 했다.
기존 버전과 차이점을 확인하면서 개발을 한다면 학습에 더 도움이 될거라 생각했다.


기존

JAVA 11
Spring Boot 2.7.8
Spring Security 5

현재

JAVA 17
Spring Boot 3.2.1
Spring Security 6.2.1


본격적인 프로젝트 진행


기존에 Spring Security에 대해 학습을 진행하긴 했지만

학습 기간중에는 비전공자인 나에게 Spring Framwork의 개념과 사용법을 익히는데만
많은 시간이 소비되어 Security 부분은 제대로 학습을 진행하지 못했었다.

이번에 완전히 이해를 하고 넘어가기 위해서 공식문서를 비교하며 하나하나 뜯어보기로 했다.

이번 시리즈에서는 기존코드와 차이점을 다루고
추가로 시리즈를 작성하여 Security안에있는 Filterchain들에 대해 더 학습해보겠다.


Security Configuration


깃헙 링크

Spring Security를 활용함에 있어 제일먼저 작성되야할 클래스는 SecurityConfiguration 클래스이다.

해당 클래스에는 Security에 가장 기본이 되는 filterchain 을 구성하기 위해 작성된다.

기존에 프로젝트에서 사용했던 코드와 비교하며 차이점을 알아보도록 하겠습니다.

기존

Spring Security 5 버전


@Configuration
public class SecurityConfiguration {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{ //
        http.headers().frameOptions().sameOrigin()
                .and()
                .csrf().disable()
                .cors().configurationSource(corsConfigurationSource())
                .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .formLogin().disable()
                .httpBasic().disable()
                .apply(new CustomFilterConfigurer())
                .and()
                .authorizeHttpRequests(authorize -> authorize
                        .antMatchers(HttpMethod.POST, "/members/**").permitAll()
                        .antMatchers(HttpMethod.PATCH, "/members/**").permitAll()
                        .antMatchers(HttpMethod.DELETE, "/members/**").permitAll()
                        .antMatchers(HttpMethod.GET, "/members/**").permitAll()
                        .anyRequest().permitAll());
        return http.build();
    }

현재

Srping Security 6 버전

@Configuration
@EnableWebSecurity
public class SecurityConfiguration {

@Bean
    public SecurityFilterChain basicConfig (HttpSecurity http) throws Exception {
        http

                .csrf(AbstractHttpConfigurer::disable) 
                //  CSRF 비활성화 대체가능 .csrf((csrf) -> csrf.disable())
                 
                .formLogin(AbstractHttpConfigurer::disable)
                // formLogin 비활성화 대체 가능 .formLogin((formLogin) -> formLogin.disable())
                
                // 로컬 개발일 경우 sameOrigin 사용하여 동일출처 허용
                .httpBasic(AbstractHttpConfigurer::disable) //

                //토큰 방식 활용을 위해 Session Stateless 설정
                .sessionManagement((session) -> session
                        .sessionCreationPolicy(SessionCreationPolicy.STATELESS))

                .headers(headers -> headers
                        .frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))


                //CORS withDefaults 사용 시 Bean 으로 등록된 corsConfigurationSource 을 사용합니다.
                //.configurationSource(apiConfigurationSource())) 메서드 명으로 커스텀 가능
                .cors(withDefaults())

                
                .securityMatcher("/api/**", "/app/**")
                .authorizeHttpRequests((authz) -> authz
                                .requestMatchers("/api/admin/**").hasRole("ADMIN")
                                .anyRequest().authenticated()




                );


        return http.build();
    }
	
    // cors(withDefaults()) 의 구현체 
    
    @Bean 
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        ...
        ...
        ...
    }


변경점


표현식 변경

Security 5 버전에서는 Lambda 표현식이 권장사항 이었고 필수사항은 아니었지만
Security 6 버전부터는 필수사항으로 변경되었습니다.

자세한 작성법은 공식문서 또는 상단에 작성된 Security 6 버전을 참고해주시기 바랍니다.

공식문서에서는 다음과 같이 말하고 있습니다.
참조 - LamdaDSL 작성법 (공식문서)

The Lambda DSL was created to accomplish to following goals:

  1. Automatic indentation makes the configuration more readable.
  2. The is no need to chain configuration options using .and().
  3. The Spring Security DSL has a similar configuration style to other Spring DSLs such as Spring Integration and Spring Cloud Gateway.

WebSecurityConfigurerAdapter

SecurityConfiguration 클래스를 작성할때 많이 등장하는
WebSecurityConfigurerAdapter 는 Spring Security 6버전 부터는 deprecated 되었습니다.

그에따라 @Override를 통해 filterchain을 구성하던 방식또한 사라지고
@Configuration@Bean 을 활용하여 filterchain을 구성합니다.

참조 - deprecated된 WebSecurityConfigurerAdapter 대처법 (블로그)

@EnableWebSecurity

위 내용과 이어지는 내용으로 WebSecurityConfigurerAdapter 가 deprecated 되고
@Configurtaion@Bean 을 통한 filterchain 구성이 권장되면서

@EnableWebSecurity@Configurtaion 를 분리하였습니다.

그리하여 공식문서에서는 @EnableWebSecurity 등과 같은 어노테이션을 활용할때
@Configuration 어노테이션을 추가해야한다고 알려주고있습니다.

참조 - Configuration 변경점 (공식문서)

Add @Configuration annotation

In 6.0, @Configuration is removed from @EnableWebSecurity, @EnableMethodSecurity, @EnableGlobalMethodSecurity, and @EnableGlobalAuthentication.

To prepare for this, wherever you are using one of these annotations, you may need to add @Configuration.

@EnableWebMvcSecurity

저는 학습을 진행할때와 현재도 XML 방식은 활용하고 있지 않지만
추후에 활용할 가능성이 있기 때문에 남겨놓습니다.

@EnableWebMvcSecurity 는 4.0 버전에서 deprecated 되었고,
@EnableWebSecurity 로 대체되었습니다.

참조 - XML 사용시 Mvc 적용 변경점 (공식문서)

authorizeHttpRequests 와 securityMatcher

authorizeHttpRequests 에서 기존에 사용되던 antMatchers mvcMatchers regexMatchers 는 deprecated 되고 새로운 requestMatcher가 등장합니다.

새로등장한 securityMatcher 는 URL 경로에 Mvc가 포함되면 기존의 mvcMatcher 와 같이 동작하고 그 외에는 antMatcher 와 같이 동작한다고 합니다.

공식문서에는 아래와 같이 나와있습니다.

참조 - requestMatcher 변경점 (공식문서)

the securityMatchers methods are similar to the requestMatchers methods in the sense that they will choose the most appropriate RequestMatcher implementation for your application. In summary, the new methods choose the MvcRequestMatcher implementation if your application has Spring MVC in the classpath, falling back to the AntPathRequestMatcher implementation if Spring MVC is not present

antMatcher

antMatcherssecurityMatcher 로 대체 됩니다.

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .antMatcher("/api/**", "/app/**")
		...
        );
    return http.build();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .securityMatcher("/api/**", "/app/**")
		...
        );
    return http.build();
}

mvcMatcher

mvcMatcherMvcRequestMatcher.Builder 를 활용 하여 아래와 같이 변경됩니다.

        MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector).servletPath("/path");
        http
            .authorizeHttpRequests((authz) -> authz
                .requestMatchers(mvcMatcherBuilder.pattern("/admin")).hasRole("ADMIN")
                .requestMatchers(mvcMatcherBuilder.pattern("/user")).hasRole("USER")
                .anyRequest().authenticated()

securityMatcher

공식문서에서는 다음과같이 securityMatcherrequestMatcher 의 용도별 활용을 권장하고 있습니다.

Another reason for adding the securityMatchers methods is to avoid confusion with the requestMatchers methods from authorizeHttpRequests.

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .securityMatchers((matchers) -> matchers
            .requestMatchers("/api/**", "/app/**", "/admin/**")
            .requestMatchers(new MyCustomRequestMatcher())
        )
        .authorizeHttpRequests((authz) -> authz
            .requestMatchers("/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated()
        );
    return http.build();
}

CustomRequestMatcher

기존에 사용되던 메서드들도 Custom 하여 사용가능합니다.

If you are having problem with the new requestMatchers methods, you can always switch back to the RequestMatcher implementation that you were using. For example, if you still want to use AntPathRequestMatcher and RegexRequestMatcher implementations, you can use the requestMatchers method that accepts a RequestMatcher instance:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .requestMatcher(new MyCustomRequestMatcher())
        .authorizeHttpRequests((authz) -> authz
            .requestMatchers("/api/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated()
        );
    return http.build();
}

public class MyCustomRequestMatcher implements RequestMatcher {
	 ...
}

0개의 댓글