์คํ๋ง๋ถํธ 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
| 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).
|
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).
|
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"))
์ด๋ฐ ์์ผ๋ก ๊ณ ์ณ์ผ ํ๋ค.