로컬에서 개발할 때 h2 In-Memory DB를 사용하던 중, h2.console.enabled 설정을 true로 하고 애플리케이션을 기동시켰는데 애플리케이션 기동이 안되고 오류가 발생했다.
This is because there is more than one mappable servlet
in your servlet context: {org.h2.server.web.JakartaWebServlet=[/h2-console/*], org.springframework.web.servlet.DispatcherServlet=[/]}.
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). This is because there is more than one mappable servlet in your servlet context: {org.h2.server.web.JakartaWebServlet=[/h2-console/*], org.springframework.web.servlet.DispatcherServlet=[/]}.
오류가 발생한 이유를 요약하자면 다음과 같다.
1. Servlet Context에 기본 DispatcherServlet 외에 H2-Console 서블릿이 추가로 등록됨
2. http.requestMatchers 메소드가 URL 매핑 할 때, 어떤 서블릿의 URL인지 알 수 없어서 충돌 발생
SecurityConfig를 수정안하고 해결할 수 있는 방법을 찾아보았지만 결국 찾지 못했고,
에러 로그에서 제공한 가이드인 requestMatchers에 AntPathRequestMatcher로 URL을 한번 감싸서 매핑하는 방법을 선택했다.
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
...
http.authorizeHttpRequests((authorizeRequests) ->
authorizeRequests
.requestMatchers("/users/**").permitAll()
.requestMatchers("/h2-console/**").permitAll()
.anyRequest().authenticated()
)
...
return http.build();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
...
http.authorizeHttpRequests((authorizeRequests) ->
authorizeRequests
.requestMatchers(new AntPathRequestMatcher("/users/login")).permitAll()
.requestMatchers(new AntPathRequestMatcher("/users/join")).permitAll()
.requestMatchers(new AntPathRequestMatcher("/error")).permitAll()
.requestMatchers(new AntPathRequestMatcher("/h2-console/**")).permitAll()
.requestMatchers(new AntPathRequestMatcher("/users/admin")).hasRole(RoleType.ADMIN.getType())
.anyRequest().authenticated()
)
...
return http.build();
}