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?
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
The dependency springdoc-openapi-ui is not applicable to spring boot 3. I remo