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=[/]}.
새롭게 고통받았던 오류이다.
springboot 3.x 와 h2를 사용할 때 발생하는 이슈라고 한다.
원인은 Spring Security는 Spring MVC 엔드포인트와 일반 AntPath 패턴에 대해 서로 다른 요청 매처를 사용하는데 패턴이 모호해서라고 한다.
Spring MVC 엔드포인트인 경우 requestMatchers(MvcRequestMatcher) 를, 아니면 antMatchers() 를 사용하라고 한다.
requestMatcher(xxxx) 를 AntPathRequestMatcher.antMatcher(xxx) 로 수정해주어서 해결
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf(AbstractHttpConfigurer::disable)
.authorizeRequests(request -> request
.requestMatchers(AntPathRequestMatcher.antMatcher("/api/v1/auth/**")).permitAll()
.requestMatchers(AntPathRequestMatcher.antMatcher("/api/v1/admin/**")).hasAnyAuthority(Role.ADMIN.name())
.requestMatchers(AntPathRequestMatcher.antMatcher("/api/v1/user/**")).hasAnyAuthority(Role.USER.name())
.anyRequest().authenticated())
.sessionManagement(manager -> manager.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authenticationProvider(authenticationProvider())
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.headers(h-> h.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable));
return http.build();
}
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"] with root cause
java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
비밀번호를 인코딩하지 않고 저장한 경우 발생하는 오류라고 한다.
나의 경우에는 인코딩 객체를 잘못 만들어줘서 발생했었다.
@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
처음엔 위처럼 썼었는데 이 매서드는 id를 반환하지 않음. 그래서 id가 null어쩌고 오류가 발생한 것.
따라서
@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder("bcrypt");
}
이렇게 id를 지정해주거나 (여기서 id는 bcrypt)
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
BCryptPasswordEncoder를 사용하면 된다.