Sec:authorize non funziona correttamente: dove sbaglio?

di il
8 risposte

Sec:authorize non funziona correttamente: dove sbaglio?

Sec:authorize non funziona correttamente: dove sbaglio?
Per la verità funziona alla grande isAuthenticated() ma non hasRole('ruolo_amministratore').
Cosa devo fare per individuarne la causa?
Su Google e precisamente su altri forum ho trovato discussioni simili ma non ho risolto.
<!DOCTYPE HTML>
<html
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:th="http://www.thymeleaf.org"
        xmlns:sec="http://www.thymeleaf.org/extras/spring-security"
        th:lang="it"
>
<head>
    <title th:utext="${titolo}"></title>
    <link th:replace="_layout :: favicon">
    <link th:replace="_layout :: stile">
    <meta charset="UTF-8">
</head>
<body>
<div th:replace="_layout :: menu"></div>
<h2><span th:utext="${messaggio}"></span></h2>
<img th:src="@{/immagini/favicon.png}" alt="Logo applicazione">

<!--/* FONTE: https://www.thymeleaf.org/doc/articles/springsecurity.html */-->
<div sec:authorize="hasRole('ruolo_amministratore')">
    Amministratore
</div>

<div sec:authorize="isAuthenticated()">
    Utente registrato
</div>

</body>
</html>

package it.applicazionijava.gestioneutenti.registrazione_spring_security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.config.core.GrantedAuthorityDefaults;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import javax.sql.DataSource;

@Configuration
@EnableWebSecurity
public class ConfigurazioneSpringSecurity extends WebSecurityConfigurerAdapter {

    @Bean
    GrantedAuthorityDefaults grantedAuthorityDefaults() {
        return new GrantedAuthorityDefaults("ruolo_"); 
    }

    @Autowired
    private DataSource dataSource;

    @Autowired
    GestioneUtentiSpringSecurity gestioneUtentiSpringSecurity;

    @Bean
    public BCryptPasswordEncoder metodoCrittografia() {
        return new BCryptPasswordEncoder();
    }

    @Autowired
    public void crittografiaPassword(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(gestioneUtentiSpringSecurity).passwordEncoder(metodoCrittografia());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.csrf().disable();

        http.authorizeRequests().antMatchers("/", "/login", "/logout-eseguito", "/benvenuto",
                "/registrazione", "/registrazione-eseguita","/pagineapplicazione").permitAll();

        http.authorizeRequests().antMatchers("/amministratore")
                .access("hasAnyRole('ruolo_amministratore', 'ruolo_proprietario')");

        http.authorizeRequests().antMatchers("/proprietario").access("hasRole('ruolo_proprietario')");

        http.authorizeRequests().and().exceptionHandling().accessDeniedPage("/errore-403");

        http.authorizeRequests().and().formLogin()
                .loginProcessingUrl("/pagina-login") 
                .loginPage("/login") // la pagina di accesso personalizzata con tutto il codice html;
                .defaultSuccessUrl("/amministratore") 
                .failureUrl("/login?errore=true") 
                .usernameParameter("username") 
                .passwordParameter("password") 
                .and().logout().logoutUrl("/pagina-logout") 
                .logoutSuccessUrl("/logout-eseguito");

        http.authorizeRequests().and() 
                .rememberMe().tokenRepository(this.persistentTokenRepository()) 
                .tokenValiditySeconds(365 * 24 * 60 * 60); // 24h x 365 = 1 anno (durata del token)

    }

    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl db = new JdbcTokenRepositoryImpl();
        db.setDataSource(dataSource);
        return db;
    }
}


package it.applicazionijava.gestioneutenti.registrazione_spring_security;

import it.applicazionijava.gestioneutenti.database_jdbc.Utente;
import it.applicazionijava.gestioneutenti.database_jdbc.UtenteRepository;
import it.applicazionijava.gestioneutenti.database_jdbc.RuoloRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class GestioneUtentiSpringSecurity implements UserDetailsService {

    @Autowired
    private UtenteRepository utenteRepository;

    @Autowired
    private RuoloRepository ruoloRepository;

    @Override
    public UserDetails loadUserByUsername(String nomeUtente) throws UsernameNotFoundException {
        Utente utente = this.utenteRepository.trovaUtente(nomeUtente);
        if (utente == null) {
            throw new UsernameNotFoundException("L'utente " + nomeUtente + " non è stato trovato nel database.");
        }

        List<String> ruoliUtente = this.ruoloRepository.trovaRuoliUtente(utente.getId());

        List<GrantedAuthority> grantList = new ArrayList<GrantedAuthority>();
        if (ruoliUtente != null) {
            for (String ruolo : ruoliUtente) {
                GrantedAuthority authority = new SimpleGrantedAuthority(ruolo);
                grantList.add(authority);
            }
        }

        UserDetails userDetails = (UserDetails) new User(utente.getNome(), utente.getPassword(), grantList);
        return userDetails;
    }

}
Il mio obiettivo e personalizzare il menu principale del sito e creare un menu diverso per ogni tipologia di utente (amministratore, utente semplice, ecc...) e questo sec calzerebbe davvero a meraviglia. Se funzionasse ovviamente...

8 Risposte

  • Re: Sec:authorize non funziona correttamente: dove sbaglio?

    iBaffiPro ha scritto:


    Sec:authorize non funziona correttamente: dove sbaglio?
    Domanda, giusto per chiarire e verificare il contesto: hai tra le dipendenze l'artifact
                <groupId>org.thymeleaf.extras</groupId>
                <artifactId>thymeleaf-extras-springsecurity5</artifactId>
    ??

    È questo infatti che gestisce il namespace http://www.thymeleaf.org/extras/spring-security

    Lo starter spring-boot-starter-thymeleaf NON tira dentro questo artifact. Va messo esplicitamente! Puoi comunque non mettere la versione, poiché è già tra quelle managed da Spring Boot.
  • Re: Sec:authorize non funziona correttamente: dove sbaglio?

    Si si, è già presente nel pom.xml. Se conosci un metodo più furbo per fare un ciclo if in base ai ruoli dell'utente puoi consigliarmelo.
    Usi anche tu "sec" oppure altro?
  • Re: Sec:authorize non funziona correttamente: dove sbaglio?

    <?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.5.1</version>
    		<relativePath/>
    	</parent>
    
    	<groupId>it.applicazionijava</groupId>
    
    	<artifactId>gestioneutenti</artifactId>
    
    	<version>1.0</version>
    
    	<packaging>war</packaging>
    
    	<name>gestioneutenti</name>
    
    	<description>WebApp con Spring Boot, Security, Thymeleaf e PostgreSQL</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>
    	</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/applicazionijava/gestioneutenti/CrittografarePassword.class,
    							WEB-INF/classes/application-sviluppo.properties,
    							WEB-INF/classes/templates/pagineapplicazione.html
    						</packagingExcludes>
    					</configuration>
    				</plugin>
    			</plugins>
    		</pluginManagement>
    	</build>
    </project>
    
  • Re: Sec:authorize non funziona correttamente: dove sbaglio?

    Quando arrivo ad un punto morto come questo cosa devo fare?
    Inutile andare avanti senza sapere come gestire i ruoli nell'interfaccia grafica...
  • Re: Sec:authorize non funziona correttamente: dove sbaglio?

    iBaffiPro ha scritto:


    Quando arrivo ad un punto morto come questo cosa devo fare?
    Inutile andare avanti senza sapere come gestire i ruoli nell'interfaccia grafica...
    Per verifica/debug: nel controller che riceve la richiesta per quella pagina, metti un println (o log) così
    System.out.println(SecurityContextHolder.getContext().getAuthentication().getAuthorities()
            .stream().map(a -> a.getAuthority()).collect(Collectors.joining(" , ")));
    ( import org.springframework.security.core.context.SecurityContextHolder; chiaramente e anche di Collectors)
    Questo ti stampa il/i ruolo/ruoli che sono attivi in quel momento.

    Hai messo sec:authorize="hasRole('ruolo_amministratore')"
    Quel print/log ti stampa esattamente il nome di questo ruolo?

    Se sì e NON ti funziona, c'è da indagare (perché dovrebbe funzionare in quanto sintatticamente è tutto corretto!)
    Se no, evidentemente hai sbagliato qualche impostazione sui ruoli o che altro ...
  • Re: Sec:authorize non funziona correttamente: dove sbaglio?

    Il tuo codice stampa questo:
    amministratore , gestore , utilizzatore
    Ma questo non renderizza nulla:
    
    <div sec:authorize="hasRole('amministratore')">
        Amministratore
    </div>
    
    Questo invece funziona:
    <div sec:authorize="isAuthenticated()">
        Utente registrato
    </div>
    e stampa "Utente registrato".
    Ho provato a rimuovere questo pezzo:
    
        @Bean
        GrantedAuthorityDefaults grantedAuthorityDefaults() {
            return new GrantedAuthorityDefaults(""); // Remove/cambia il prefisso ROLE_.
        }
    
    e ad usare questo:
    
    <div sec:authorize="hasRole('ROLE_amministratore')">
        Amministratore
    </div>
    
    e tutto funziona a meraviglia.
    In pratica l'errore è nel @Bean che uso per rimuovere ROLE_ dal DBMS.
    La domanda ora è un'altra: come rimuovo questo schifosissimo ROLE_?
    P.S.:
    Ho qualcosa di analogo al tuo codice:
    public class FunzioniWeb {
        public static String creaLaStringa(User user) {
            StringBuilder sb = new StringBuilder();
            sb.append("Nome Utente: ").append(user.getUsername());
            Collection<GrantedAuthority> authorities = user.getAuthorities();
            if (authorities != null && !authorities.isEmpty()) {
                sb.append(" (");
                boolean first = true;
                for (GrantedAuthority a : authorities) {
                    if (first) {
                        sb.append(a.getAuthority());
                        first = false;
                    } else {
                        sb.append(", ").append(a.getAuthority());
                    }
                }
                sb.append(")");
            }
            return sb.toString();
        }
    }
    C'è "giusto" qualche riga di codice in più...
  • Re: Sec:authorize non funziona correttamente: dove sbaglio?

    iBaffiPro ha scritto:


    La domanda ora è un'altra: come rimuovo questo schifosissimo ROLE_?
    Non saprei dire sul momento come rimuovere ROLE_, dovrei documentarmi.

    Ma dato che hai creato esplicitamente dei SimpleGrantedAuthority e hai messo nomi es. "amministratore", allora a livello di espressione metti

    sec:authorize="hasAuthority('amministratore')"

    e ti funziona.
  • Re: Sec:authorize non funziona correttamente: dove sbaglio?

    Però se uso hasAuthority in Thymeleaf poi nella classe che estende WebSecurityConfigurerAdapter posso lasciare hasRole e hasAnyRole? E' confusa questa parte relativa a ruoli e autorità e il codice che si usava un tempo non funziona più.
    Qui si parla di setDefaultRolePrefix ma non saprei come usarla.
Devi accedere o registrarti per scrivere nel forum
8 risposte