Post

Spring Security - WebSecurityConfigurerAdapter deprecated ๋Œ€์‘

๐Ÿ“Œ WebSecurityConfigurerAdapter is deprecated

์Šคํ”„๋ง๋ถ€ํŠธ 2.4๋ฒ„์ „์— ๋งŒ๋“ค์–ด์ง„ JWT ๊ฐ•์˜๋ฅผ ๋ณด๋ฉด์„œ ์ตœ์‹  ๋ฒ„์ „์˜ ํ”„๋กœ์ ํŠธ๋กœ ์ž‘์—…ํ•˜๊ณ  ์žˆ๋Š”๋ฐ ๋ฐ”๋€๊ฒŒ ๊ฝค๋‚˜ ๋งŽ๋‹ค. Spring Security 6.0 ๋ฒ„์ „ ๊ธฐ์ค€์œผ๋กœ WebSecurityConfigurerAdapter๋ฅผ ์™„์ „ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ฒŒ ๋๋‹ค. ๊ทธ๋ž˜์„œ ์–ด๋–ป๊ฒŒ ๋ฐ”๊ฟ”์•ผ ํ•˜๋Š”์ง€ ์ •๋ฆฌํ•˜๋Š” ๊ฒธ ์ž‘์„ฑํ•ด๋ณด์•˜๋‹ค.

๊ธฐ์กด์—” WebSecurityConfigurerAdapter๋ฅผ extendsํ•œ ํ›„์—, configure ๋ฉ”์†Œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋”ฉ ํ•˜๋Š” ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜์˜€๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ฐ”๋€ ๋ฐฉ์‹์€ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์ปค์Šคํ…€ ํ•  ์„ค์ •๋“ค์„ @Bean์œผ๋กœ ๋“ฑ๋กํ•˜์—ฌ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

์ด ์ฝ”๋“œ์˜ ๊ธฐ์ค€์€ ์Šคํ”„๋ง๋ถ€ํŠธ 3.1.2์ด๋‹ค.


๐Ÿฅ‘ HttpSecurity ์„ค์ •

  • ๊ธฐ์กด ๋ฐฉ์‹
1
2
3
4
5
6
7
8
9
10
11
12
13
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests((authz) -> authz
                        .anyRequest().authenticated()
                )
                .httpBasic(withDefaults());
    }
}
  • ๋ณ€๊ฒฝ๋œ ๋ฐฉ์‹
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests((authz) -> authz
                        .requestMatchers(new AntPathRequestMatcher("/api/hello")).permitAll()
                        .anyRequest().authenticated()
                )
                .httpBasic(withDefaults());

        return http.build();
    }
}


๐ŸŽˆ WebSecurity ์„ค์ •

  • ๊ธฐ์กด ๋ฐฉ์‹
1
2
3
4
5
6
7
8
9
10
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(WebSecurity web) {
        web.ignoring().antMatchers("/ignore1", "/ignore2");
    }

}
  • ๋ณ€๊ฒฝ๋œ ๋ฐฉ์‹
1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring()
                .requestMatchers(
                        new AntPathRequestMatcher("/h2-console/**"),
                        new AntPathRequestMatcher("/favicon.ico"));
    }
}


JDBC ์„ค์ •

  • ๊ธฐ์กด ๋ฐฉ์‹
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Configuration
public class SecurityConfiguration {
    @Bean
    public DataSource dataSource() {
        return new EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.H2)
            .addScript(JdbcDaoImpl.DEFAULT_USER_SCHEMA_DDL_LOCATION)
            .build();
    }

    @Bean
    public UserDetailsManager users(DataSource dataSource) {
        UserDetails user = User.withDefaultPasswordEncoder()
            .username("user")
            .password("password")
            .roles("USER")
            .build();
        JdbcUserDetailsManager users = new JdbcUserDetailsManager(dataSource);
        users.createUser(user);
        return users;
    }
}
  • ๋ณ€๊ฒฝ๋œ ๋ฐฉ์‹
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Bean
    public DataSource dataSource() {
        return new EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.H2)
            .build();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        UserDetails user = User.withDefaultPasswordEncoder()
            .username("user")
            .password("password")
            .roles("USER")
            .build();
        auth.jdbcAuthentication()
            .withDefaultSchema()
            .dataSource(dataSource())
            .withUser(user);
    }
}

์ด๊ฑด ์•„์ง ์‹คํ–‰์„ ์•ˆํ•ด๋ด์„œ ์‹ค์ œ๋กœ ์ž‘๋™ํ•˜๋Š”์ง€ ๋ชจ๋ฅด๊ฒ ๋‹ค.


+) ์ถ”๊ฐ€

  • ๊ธฐ์กด ๋ฐฉ์‹
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)

                .and()
                .httpBasic().disable()
                .formLogin().disable()
                .addFilter(corsFilter);

        http.authorizeRequests()
                .antMatchers(FRONT_URL+"/main/**")
                .authenticated()
                .anyRequest().permitAll()

                .and()
                //(1)
                .exceptionHandling()
                .authenticationEntryPoint(new CustomAuthenticationEntryPoint());

		//(2)
        http.addFilterBefore(new JwtRequestFilter(), UsernamePasswordAuthenticationFilter.class);
    }
}

  • ๋ณ€๊ฒฝ๋œ ๋ฐฉ์‹
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {

    private final CorsFilter corsFilter;
    public static final String FRONT_URL = "http://localhost:3000";

    @Bean
    public BCryptPasswordEncoder encodePwd() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .csrf(AbstractHttpConfigurer::disable)
                .sessionManagement((sessionManagement) ->
                        sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                )
                .httpBasic(AbstractHttpConfigurer::disable)
                .formLogin(AbstractHttpConfigurer::disable)
                .addFilter(corsFilter);

        http
                .authorizeRequests((authz) -> authz
                                .requestMatchers(new AntPathRequestMatcher("/**")).permitAll()
                                .requestMatchers(
                                        new AntPathRequestMatcher("/bookmark/**"),
                                        new AntPathRequestMatcher("/user/mypage/**")
                                ).hasRole(Role.USER.name())
                                .requestMatchers(new AntPathRequestMatcher("/admin/**")).hasRole(Role.ADMIN.name())
                                .anyRequest().authenticated()
                )
                .exceptionHandling((exceptionConfig) ->
                        exceptionConfig.authenticationEntryPoint(new CustomAuthenticationEntryPoint())
                );

        http
                .addFilterBefore(new JwtRequestFilter(), UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }

}

๐Ÿ“Œ requestMatchers ์—๋Ÿฌ

[์—๋Ÿฌ ๋ฉ”์‹œ์ง€] This method cannot decide whether these patterns are Spring MVC patterns or not.


  • ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ 1
1
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'filterChain' defined in class path resource [study/tutorial/jwt/config/SecurityConfig.class]: Failed to instantiate [org.springframework.security.web.SecurityFilterChain]: Factory method 'filterChain' threw exception with message: This method cannot decide whether these patterns are Spring MVC patterns or not. If this endpoint is a Spring MVC endpoint, please use requestMatchers(MvcRequestMatcher); otherwise, please use requestMatchers(AntPathRequestMatcher).
  • ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ 2
1
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.security.web.SecurityFilterChain]: Factory method 'filterChain' threw exception with message: This method cannot decide whether these patterns are Spring MVC patterns or not. If this endpoint is a Spring MVC endpoint, please use requestMatchers(MvcRequestMatcher); otherwise, please use requestMatchers(AntPathRequestMatcher).
  • ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ 3
1
Caused by: java.lang.IllegalArgumentException: This method cannot decide whether these patterns are Spring MVC patterns or not. If this endpoint is a Spring MVC endpoint, please use requestMatchers(MvcRequestMatcher); otherwise, please use requestMatchers(AntPathRequestMatcher).

์ฒ˜์Œ ๊ณ ์ณค์„ ๋• ๋Œ€์ถฉ ์ด๋Ÿฐ ์—๋Ÿฌ๋“ค์ด ๋–ด์—ˆ๋‹ค. ์ด ์—๋Ÿฌ๋Š” requestMatchers ์•ˆ์— ์ ํ˜€์žˆ๋Š” ์—”๋“œํฌ์ธํŠธ๊ฐ€ MVC ์—”๋“œํฌ์ธํŠธ์ธ์ง€ ์•„๋‹Œ์ง€ ๊ตฌ๋ถ„์„ ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๋œป์ด์—ˆ๋‹ค.

  • ๋‹น์‹œ ์ฝ”๋“œ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests((authz) -> authz
                        .requestMatchers("/api/hello").permitAll()
                        .anyRequest().authenticated())
                .httpBasic(withDefaults());

        return http.build();
    }
}

  • ๋ฐ”๋€ ์ฝ”๋“œ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests((authz) -> authz
                        .requestMatchers(new AntPathRequestMatcher("/api/hello")).permitAll()
                        .anyRequest().authenticated()
                )
                .httpBasic(withDefaults());

        return http.build();
    }
}

์œ„์˜ ์ฝ”๋“œ์ฒ˜๋Ÿผ ๊ทธ๋ƒฅ "/api/hello"๊ฐ€ ์•„๋‹Œ new AntPathRequestMatcher("/api/hello")๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. ๋งŒ์•ฝ MVC ์—”๋“œํฌ์ธํŠธ๋ผ๋ฉด .requestMatchers(new AntPathRequestMatcher("/api/hello"))๊ฐ€ ์•„๋‹Œ .requestMatchers(new MvcRequestMatcher("/api/hello")) ์ด๋Ÿฐ ์‹์œผ๋กœ ๊ณ ์ณ์•ผ ํ•œ๋‹ค.

This post is licensed under CC BY 4.0 by the author.