I made a very simple application in Spring Boot. I have used very few features offered by the framework and despite everything I have problems updating my application to the most recent versions of the framework. I also note that the support for Spring Security is disappointing because there is no dedicated community. As I wrote in the title, my needs are only 3:
In the past I have opened a thread on this forum because the documentation claims that support for Spring Security is here on Stackoverflow but I have not found a solution to my problem.
I can't update my webapp to Spring Boot 2.6.0 (2.5.7 works but 2.6.0 doesn't)
It is disarming to learn that Spring Boot applications are not updatable and even more disarming that the Spring Security team is not present on Stackoverflow. My request is very simple, how can I extend WebSecurityConfigurerAdapter and how can I implement UserDetailsService to get what I need with 2.6.x? Also, I wouldn't mind replacing javax with jakarta and trying Spring Boot 3 on JDK 17 but if the support is non-existent, the code I find doesn't work and I have to read a 1000 page book every new version of the framework the advantage of using a framework is null. I am very disappointed, I hope that some Spring Security developer wishes to intervene. Below you will find the commented code (see points 1 and 2).
To make the application work and not have this problem:
I have to use this code:
spring.main.allow-circular-references=true
But I don't want to use the above code, I want to update my application without using circular references.
Thank you
ConfigurazioneSpringSecurity extends WebSecurityConfigurerAdapter
// Configurazione di Spring Security.
@Configuration
@EnableWebSecurity
public class ConfigurazioneSpringSecurity extends WebSecurityConfigurerAdapter {
// Metodi per la gestione dell'utente autenticato.
@Autowired
GestioneUtentiSpringSecurity gestioneUtentiSpringSecurity;
// 1) Metodo per crittografare la password >> ?????????????
@Bean
public BCryptPasswordEncoder metodoCrittografia() {
return new BCryptPasswordEncoder();
}
@Autowired
public void crittografiaPassword(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(gestioneUtentiSpringSecurity).passwordEncoder(metodoCrittografia());
}
// 2.a) Pulsante "Ricordami" (l'utente non deve inserire ogni volta la password di login) >> ?????????????
@Autowired
private DataSource dataSource;
@Bean
public PersistentTokenRepository persistentTokenRepository() {
JdbcTokenRepositoryImpl db = new JdbcTokenRepositoryImpl();
db.setDataSource(dataSource);
return db;
}
// Se l'utente cambia la password il pulsante "Ricordami" continua a funzionare.
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
// Configurazione di Spring Security.
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests().antMatchers(
"/",
"/login",
"/benvenuto",
"/registrazione",
"/registrazione-eseguita",
"/pagine-applicazione"
).permitAll();
http.authorizeRequests().antMatchers("/area-riservata")
.access("hasAnyRole('" + livelliDeiRuoli.elencoRuoli(1L) + "')");
// ... ecc...
http.authorizeRequests().and().exceptionHandling().accessDeniedPage("/errore-403");
http.authorizeRequests().and().formLogin()
.loginProcessingUrl("/pagina-login")
.loginPage("/login")
.defaultSuccessUrl("/")
.failureUrl("/login?errore=true")
.usernameParameter("username")
.passwordParameter("password")
.and().logout().logoutUrl("/pagina-logout")
.logoutSuccessUrl("/login?logout=true");
// 2.b) Pulsante "Ricordami" (l'utente non deve inserire ogni volta la password di login) >> ?????????????
http.authorizeRequests().and()
.rememberMe().tokenRepository(this.persistentTokenRepository())
.tokenValiditySeconds(365 * 24 * 60 * 60);
}
}
GestioneUtentiSpringSecurity implements UserDetailsService
// Creazione utente autenticato.
@Service
public class GestioneUtentiSpringSecurity implements UserDetailsService {
@Autowired
private UtenteRepository utenteRepository;
@Autowired
private RuoloRepository ruoloRepository;
@Autowired
//...
// Creazione utente autenticato
@Override
public UserDetails loadUserByUsername(String nomeUtente) throws UsernameNotFoundException {
// Si cerca l'utente nel database
Utente utente = trovaUtenteConPrivilegiDiAutenticazione(nomeUtente);
if (utente == null) {
// System.out.println("L'utente " + nomeUtente + " non è stato trovato!");
throw new UsernameNotFoundException("L'utente " + nomeUtente + " non è stato trovato nel database.");
}
// Si cercano i ruoli dell'utente
List<String> ruoliUtente = null;
try {
ruoliUtente = this.ruoloRepository.trovaRuoliUtente(utente.getId());
}catch (Exception b){
ruoliUtente = null;
}
// Si caricano in una lista di oggetti GrantedAuthority i ruoli di un dato utente.
// GrantedAuthority è una classe di Spring Security che contiene i privilegi di un utente.
List<GrantedAuthority> grantList = null;
try{
grantList = new ArrayList<GrantedAuthority>();
if (ruoliUtente != null) {
for (String ruolo : ruoliUtente) {
GrantedAuthority authority = new SimpleGrantedAuthority(ruolo);
grantList.add(authority);
}
}
}catch (Exception c){
grantList = null;
}
// Si crea un oggetto specifico di Spring Security che rappresenta l'utente autenticato. Questo oggetto contiene 3
// informazioni: nome utente, password e privilegi. Questi ultimi, in questa applicazione si fanno coincidere
// con i ruoli.
UserDetails userDetails = null;
if((utente != null) && (ruoliUtente != null) && (grantList != null)){
userDetails = (UserDetails) new User(utente.getNome(), utente.getPassword(), grantList);
}
return userDetails;
}
// Si cerca l'utente nel database
public Utente trovaUtenteConPrivilegiDiAutenticazione(String nomeUtente){
// ...
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.4</version>
<relativePath/> <!--/* cerca genitore dal repository */-->
</parent>
<groupId>...</groupId>
<artifactId>...</artifactId>
<version>...</version>
<packaging>war</packaging>
<name>...</name>
<description>...</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</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-web</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
<version>1.9.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.1</version>
</dependency>
</dependencies>
<build>
<finalName>gestioneutenti</finalName>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<packagingExcludes>
WEB-INF/classes/it/...
</packagingExcludes>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
Please try declaring the factory method of the password encoder static
:
@Bean
public static BCryptPasswordEncoder metodoCrittografia() {
return new BCryptPasswordEncoder();
}
This makes it clear to Spring that their is no actual dependency on other beans injected into ConfigurazioneSpringSecurity
.
This solves the problem at least in simpler setups: Spring boot 2.6.0 Error creating bean with name 'webSecurityConfig'
It's hard to say for sure, as your code snippet is quite long and yet incomplete. If the suggestion above should not work, please consider providing the full log of the failed application start-up or a smaller yet complete sample that reproduces the problem.