I had a Spring Boot 2.7.6 app with Spring Security 5.7.5 running without problems: authentication works, I navigate through the different pages according to roles, Swagger UI is usable, etc. I don’t have a deprecated warning for your information.
I migrated to Spring Boot 3.0.0 and therefore Spring Security 6.0.0. I followed the migration guides and the server starts without error. But my URLs no longer work. I have a 401 status.
Issue #1: GET http://localhost:8080/swagger-ui/index.html
results in a 401 on client side.
In the logs I have a 404:
DEBUG o.s.web.servlet.handler.SimpleUrlHandlerMapping : Mapped to ResourceHttpRequestHandler [classpath [static/]] DEBUG o.s.web.servlet.handler.SimpleUrlHandlerMapping : Mapped to ResourceHttpRequestHandler [classpath [static/]] DEBUG o.s.web.servlet.handler.SimpleUrlHandlerMapping : Mapped to ResourceHttpRequestHandler [classpath [static/]] DEBUG o.s.web.servlet.handler.SimpleUrlHandlerMapping : Mapped to ResourceHttpRequestHandler [classpath [static/]] DEBUG org.springframework.web.servlet.DispatcherServlet : GET "/swagger-ui/index.html", parameters={} DEBUG o.s.web.servlet.handler.SimpleUrlHandlerMapping : Mapped to ResourceHttpRequestHandler [classpath [static/]] DEBUG o.s.w.servlet.resource.ResourceHttpRequestHandler : Resource not found DEBUG org.springframework.web.servlet.DispatcherServlet : Completed 404 NOT_FOUND DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#errorHtml(HttpServletRequest, HttpServletResponse) DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#errorHtml(HttpServletRequest, HttpServletResponse) DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#errorHtml(HttpServletRequest, HttpServletResponse)
pom.xml
... <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.0.0</version> <relativePath /> <!-- lookup parent from repository --> </parent> ... <properties> <java.version>17</java.version> <jjwt.version>0.11.5</jjwt.version> <springdoc.version>1.6.0</springdoc.version> <docx4j.version>11.3.2</docx4j.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-core</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.liquibase</groupId> <artifactId>liquibase-core</artifactId> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-collections4</artifactId> <version>4.4</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>${jjwt.version}</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>${jjwt.version}</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <version>${jjwt.version}</version> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-ui</artifactId> <version>${springdoc.version}</version> </dependency> <dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-security</artifactId> <version>${springdoc.version}</version> </dependency> <dependency> <groupId>org.docx4j</groupId> <artifactId>docx4j-export-fo</artifactId> <version>${docx4j.version}</version> </dependency> <dependency> <groupId>org.docx4j</groupId> <artifactId>docx4j-JAXB-ReferenceImpl</artifactId> <version>${docx4j.version}</version> </dependency> <dependency> <groupId>jakarta.xml.bind</groupId> <artifactId>jakarta.xml.bind-api</artifactId> <version>3.0.1</version> </dependency> <dependency> <groupId>jakarta.xml.bind</groupId> <artifactId>jakarta.xml.bind-api-parent</artifactId> <version>3.0.1</version> <type>pom</type> </dependency> </dependencies> ... </project>
SecurityConfig
class
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpStatus; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.HttpStatusEntryPoint; import org.springframework.security.web.context.RequestAttributeSecurityContextRepository; import org.springframework.security.web.savedrequest.HttpSessionRequestCache; @Configuration @EnableWebSecurity @EnableMethodSecurity(securedEnabled = true, jsr250Enabled = true) public class SecurityConfig { @Autowired UserDetailsService userDetailsService; @Autowired public void configureGlobal(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception { authenticationManagerBuilder.getDefaultUserDetailsService(); } // @Override // public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception { // authenticationManagerBuilder.userDetailsService(this.userDetailsService) // .passwordEncoder(passwordEncoder()); // } @Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception { return authenticationConfiguration.getAuthenticationManager(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean SecurityFilterChain filterChain(HttpSecurity http) throws Exception { // @formatter:off http .headers() .frameOptions().disable() .and() .cors() .and() .csrf().disable() .exceptionHandling() .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)).and() .formLogin().disable() .authorizeHttpRequests(authz -> authz.requestMatchers("/api/*/auth/**").permitAll() .requestMatchers("/api/*/public/**").permitAll() .requestMatchers("/api/*/catalogs/*/documents/*/file").permitAll() .requestMatchers(req -> req.getRequestURI() .contains("swagger-ui")).permitAll() .anyRequest().authenticated()); // @formatter:on return http.build(); } @Bean public WebSecurityCustomizer webSecurityCustomizer() { return (web) -> web.ignoring() .requestMatchers(req -> req.getRequestURI() .contains("mail-images")) .requestMatchers(req -> req.getRequestURI() .contains("api-docs")) // .requestMatchers(req -> req.getRequestURI() // .contains("swagger-ui")) .requestMatchers(req -> req.getRequestURI() .contains("h2-console")); } }
WebMvcConfig
class
import java.util.List; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration @EnableWebMvc public class WebMvcConfig implements WebMvcConfigurer { @Value("#{'${cors.allowedOrigins}'.split(',')}") private List<String> allowedOrigins; @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowCredentials(true) .allowedHeaders("*") .allowedOriginPatterns("http://*", "https://*") .allowedOrigins(this.allowedOrigins.toArray(String[]::new)) .allowedMethods(HttpMethod.GET.name(), HttpMethod.POST.name(), HttpMethod.PUT.name(), HttpMethod.PATCH.name(), HttpMethod.DELETE.name(), HttpMethod.OPTIONS.name()); } private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {"classpath:/static/"}; @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/**") .addResourceLocations(CLASSPATH_RESOURCE_LOCATIONS); } }
I tried some differents configuration according with
- https://docs.spring.io/spring-security/reference/5.8/migration/
- https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Migration-Guide
Do you have a search lead because I’m drying up after several attempts?
Advertisement
Answer
I found the solution : with spring boot 3 it seems to use springdoc-openapi-starter-webmvc-ui (https://springdoc.org/v2/). I have added the following dependency and now i can use swagger
<dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> <version>2.0.2</version> </dependency>
The dependency springdoc-openapi-ui is not applicable to spring boot 3. I remo