web-dev-qa-db-fra.com

Spring Boot Security + Thymeleaf: classe IProcessorDialect manquante

J'essaie d'intégrer le dialecte de sécurité Thymeleaf (tel que la balise sec: authorize) dans une application Spring Boot + Spring Security qui fonctionne correctement.

Après quelques recherches, j'ai trouvé que la solution pour l'activer est de:

Ajoutez la dépendance dans le fichier POM:

<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-springsecurity4</artifactId>
    <version>3.0.0.RELEASE</version>
</dependency>

et incluez la balise en haut du fichier de modèle:

<html   xmlns:th="http://www.thymeleaf.org" lang="en"
        xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">

Jusqu'ici tout va bien. La dépendance est trouvée, les balises reconnues dans le balisage.

Cependant, ils ne sont pas pris en compte et apparaissent dans le code HTML final généré.

En raison d'un problème d'auto-configuration de Spring Boot qui n'active pas, il semble nécessaire d'ajouter manuellement un SpringSecurityDialect Bean à une classe @Configuration pour l'activer (plusieurs questions trouvées sur StackOverflow ont été résolues par ce):

@Bean
    public SpringSecurityDialect securityDialect() {
        return new SpringSecurityDialect();
    }

C'est ce qui cause un problème: lorsque j'ajoute ce bean dans ma configuration de démarrage Spring, il génère une exception car il ne trouve pas la classe org.thymeleaf.dialect.IProcessorDialect . Voici l'erreur:

> Java.lang.IllegalStateException: Could not evaluate condition on
> org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration#propertySourcesPlaceholderConfigurer
> due to org/thymeleaf/dialect/IProcessorDialect not found. Make sure
> your own configuration does not rely on that class. This can also
> happen if you are @ComponentScanning a springframework package (e.g.
> if you put a @ComponentScan in the default package by mistake)

Qu'est-ce que je rate? Est-ce une erreur venant de Thymeleaf? Botte de printemps? Mon propre code? Merci d'avance pour votre aide !

Voici quelques-uns de mes fichiers concernés par mon problème:

Application.Java

@SpringBootApplication
public class Application extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
      public EmbeddedServletContainerFactory servletContainer() {
        TomcatEmbeddedServletContainerFactory Tomcat = new TomcatEmbeddedServletContainerFactory() {
            @Override
            protected void postProcessContext(Context context) {
              SecurityConstraint securityConstraint = new SecurityConstraint();
              securityConstraint.setUserConstraint("CONFIDENTIAL");
              SecurityCollection collection = new SecurityCollection();
              collection.addPattern("/*");
              securityConstraint.addCollection(collection);
              context.addConstraint(securityConstraint);
            }
          };

        Tomcat.addAdditionalTomcatConnectors(initiateHttpConnector());
        return Tomcat;
      }

      private Connector initiateHttpConnector() {
        Connector connector = new Connector("org.Apache.coyote.http11.Http11NioProtocol");
        connector.setScheme("http");
        connector.setPort(8080);
        connector.setSecure(false);
        connector.setRedirectPort(8443);

        return connector;
      }
}

WebMvcConfig.Java

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.thymeleaf.extras.springsecurity4.dialect.SpringSecurityDialect;

@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {

    /**
     * Configure relationships between URLs and view names
     */
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
    }

    @Bean
    public SpringSecurityDialect securityDialect() {
        return new SpringSecurityDialect();
    }
}

Modèle Thymeleaf:

<!DOCTYPE html>
<html   xmlns:th="http://www.thymeleaf.org" lang="en"
        xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">

....

<div sec:authorize="isAuthenticated()">
    LOGGED IN
</div>
<div sec:authorize="isAnonymous()">
    ANONYMOUS
</div>

....

La sortie complète de la console lors du démarrage de l'application:

>  :: Spring Boot ::        (v1.3.4.RELEASE)
> 
> 2016-05-17 17:22:59.951  INFO 96267 --- [  restartedMain]
> edu.rmit.eres.estored.Application        : Starting Application on
> w8031808.local with PID 96267
> (/Users/guillaume/dev/workspace/e-stored/target/classes started by
> guillaume in /Users/guillaume/dev/workspace/e-stored) 2016-05-17
> 17:22:59.956  INFO 96267 --- [  restartedMain]
> edu.rmit.eres.estored.Application        : No active profile set,
> falling back to default profiles: default 2016-05-17 17:23:00.239 
> INFO 96267 --- [  restartedMain]
> ationConfigEmbeddedWebApplicationContext : Refreshing
> org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@16f53cde:
> startup date [Tue May 17 17:23:00 AEST 2016]; root of context
> hierarchy 2016-05-17 17:23:01.578 ERROR 96267 --- [  restartedMain]
> o.s.boot.SpringApplication               : Application startup failed
> 
> Java.lang.IllegalStateException: Could not evaluate condition on
> org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration#propertySourcesPlaceholderConfigurer
> due to org/thymeleaf/dialect/IProcessorDialect not found. Make sure
> your own configuration does not rely on that class. This can also
> happen if you are @ComponentScanning a springframework package (e.g.
> if you put a @ComponentScan in the default package by mistake)    at
> org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.Java:55)
> ~[spring-boot-autoconfigure-1.3.4.RELEASE.jar:1.3.4.RELEASE]  at
> org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.Java:102)
> ~[spring-context-4.2.6.RELEASE.jar:4.2.6.RELEASE]     at
> org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForBeanMethod(ConfigurationClassBeanDefinitionReader.Java:178)
> ~[spring-context-4.2.6.RELEASE.jar:4.2.6.RELEASE]     at
> org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.Java:140)
> ~[spring-context-4.2.6.RELEASE.jar:4.2.6.RELEASE]     at
> org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.Java:116)
> ~[spring-context-4.2.6.RELEASE.jar:4.2.6.RELEASE]     at
> org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.Java:333)
> ~[spring-context-4.2.6.RELEASE.jar:4.2.6.RELEASE]     at
> org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.Java:243)
> ~[spring-context-4.2.6.RELEASE.jar:4.2.6.RELEASE]     at
> org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.Java:273)
> ~[spring-context-4.2.6.RELEASE.jar:4.2.6.RELEASE]     at
> org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.Java:98)
> ~[spring-context-4.2.6.RELEASE.jar:4.2.6.RELEASE]     at
> org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.Java:678)
> ~[spring-context-4.2.6.RELEASE.jar:4.2.6.RELEASE]     at
> org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.Java:520)
> ~[spring-context-4.2.6.RELEASE.jar:4.2.6.RELEASE]     at
> org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.Java:118)
> ~[spring-boot-1.3.4.RELEASE.jar:1.3.4.RELEASE]    at
> org.springframework.boot.SpringApplication.refresh(SpringApplication.Java:766)
> [spring-boot-1.3.4.RELEASE.jar:1.3.4.RELEASE]     at
> org.springframework.boot.SpringApplication.createAndRefreshContext(SpringApplication.Java:361)
> [spring-boot-1.3.4.RELEASE.jar:1.3.4.RELEASE]     at
> org.springframework.boot.SpringApplication.run(SpringApplication.Java:307)
> [spring-boot-1.3.4.RELEASE.jar:1.3.4.RELEASE]     at
> org.springframework.boot.SpringApplication.run(SpringApplication.Java:1191)
> [spring-boot-1.3.4.RELEASE.jar:1.3.4.RELEASE]     at
> org.springframework.boot.SpringApplication.run(SpringApplication.Java:1180)
> [spring-boot-1.3.4.RELEASE.jar:1.3.4.RELEASE]     at
> edu.rmit.eres.estored.Application.main(Application.Java:24)
> [classes/:na]     at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native
> Method) ~[na:1.8.0_60]    at
> Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:62)
> ~[na:1.8.0_60]    at
> Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43)
> ~[na:1.8.0_60]    at Java.lang.reflect.Method.invoke(Method.Java:497)
> ~[na:1.8.0_60]    at
> org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.Java:49)
> [spring-boot-devtools-1.3.4.RELEASE.jar:1.3.4.RELEASE] Caused by:
> Java.lang.NoClassDefFoundError:
> org/thymeleaf/dialect/IProcessorDialect   at
> Java.lang.ClassLoader.defineClass1(Native Method) ~[na:1.8.0_60]  at
> Java.lang.ClassLoader.defineClass(ClassLoader.Java:760) ~[na:1.8.0_60]
>   at
> Java.security.SecureClassLoader.defineClass(SecureClassLoader.Java:142)
> ~[na:1.8.0_60]    at
> Java.net.URLClassLoader.defineClass(URLClassLoader.Java:467)
> ~[na:1.8.0_60]    at
> Java.net.URLClassLoader.access$100(URLClassLoader.Java:73)
> ~[na:1.8.0_60]    at
> Java.net.URLClassLoader$1.run(URLClassLoader.Java:368) ~[na:1.8.0_60]
>   at Java.net.URLClassLoader$1.run(URLClassLoader.Java:362)
> ~[na:1.8.0_60]    at Java.security.AccessController.doPrivileged(Native
> Method) ~[na:1.8.0_60]    at
> Java.net.URLClassLoader.findClass(URLClassLoader.Java:361)
> ~[na:1.8.0_60]    at
> Java.lang.ClassLoader.loadClass(ClassLoader.Java:424) ~[na:1.8.0_60]
>   at Sun.misc.Launcher$AppClassLoader.loadClass(Launcher.Java:331)
> ~[na:1.8.0_60]    at
> Java.lang.ClassLoader.loadClass(ClassLoader.Java:357) ~[na:1.8.0_60]
>   at
> org.springframework.boot.devtools.restart.classloader.RestartClassLoader.loadClass(RestartClassLoader.Java:151)
> ~[spring-boot-devtools-1.3.4.RELEASE.jar:1.3.4.RELEASE]   at
> Java.lang.ClassLoader.loadClass(ClassLoader.Java:357) ~[na:1.8.0_60]
>   at Java.lang.Class.getDeclaredMethods0(Native Method) ~[na:1.8.0_60]
>   at Java.lang.Class.privateGetDeclaredMethods(Class.Java:2701)
> ~[na:1.8.0_60]    at Java.lang.Class.getDeclaredMethods(Class.Java:1975)
> ~[na:1.8.0_60]    at
> org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.Java:612)
> ~[spring-core-4.2.6.RELEASE.jar:4.2.6.RELEASE]    at
> org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.Java:524)
> ~[spring-core-4.2.6.RELEASE.jar:4.2.6.RELEASE]    at
> org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.Java:510)
> ~[spring-core-4.2.6.RELEASE.jar:4.2.6.RELEASE]    at
> org.springframework.util.ReflectionUtils.getUniqueDeclaredMethods(ReflectionUtils.Java:570)
> ~[spring-core-4.2.6.RELEASE.jar:4.2.6.RELEASE]    at
> org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryMethod(AbstractAutowireCapableBeanFactory.Java:683)
> ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE]   at
> org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.Java:627)
> ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE]   at
> org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.Java:597)
> ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE]   at
> org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.Java:1445)
> ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE]   at
> org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.Java:975)
> ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE]   at
> org.springframework.boot.autoconfigure.condition.BeanTypeRegistry$OptimizedBeanTypeRegistry.addBeanTypeForNonAliasDefinition(BeanTypeRegistry.Java:289)
> ~[spring-boot-autoconfigure-1.3.4.RELEASE.jar:1.3.4.RELEASE]  at
> org.springframework.boot.autoconfigure.condition.BeanTypeRegistry$OptimizedBeanTypeRegistry.addBeanType(BeanTypeRegistry.Java:278)
> ~[spring-boot-autoconfigure-1.3.4.RELEASE.jar:1.3.4.RELEASE]  at
> org.springframework.boot.autoconfigure.condition.BeanTypeRegistry$OptimizedBeanTypeRegistry.getNamesForType(BeanTypeRegistry.Java:259)
> ~[spring-boot-autoconfigure-1.3.4.RELEASE.jar:1.3.4.RELEASE]  at
> org.springframework.boot.autoconfigure.condition.OnBeanCondition.collectBeanNamesForType(OnBeanCondition.Java:182)
> ~[spring-boot-autoconfigure-1.3.4.RELEASE.jar:1.3.4.RELEASE]  at
> org.springframework.boot.autoconfigure.condition.OnBeanCondition.getBeanNamesForType(OnBeanCondition.Java:171)
> ~[spring-boot-autoconfigure-1.3.4.RELEASE.jar:1.3.4.RELEASE]  at
> org.springframework.boot.autoconfigure.condition.OnBeanCondition.getMatchingBeans(OnBeanCondition.Java:139)
> ~[spring-boot-autoconfigure-1.3.4.RELEASE.jar:1.3.4.RELEASE]  at
> org.springframework.boot.autoconfigure.condition.OnBeanCondition.getMatchOutcome(OnBeanCondition.Java:113)
> ~[spring-boot-autoconfigure-1.3.4.RELEASE.jar:1.3.4.RELEASE]  at
> org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.Java:47)
> ~[spring-boot-autoconfigure-1.3.4.RELEASE.jar:1.3.4.RELEASE]  ... 22
> common frames omitted Caused by: Java.lang.ClassNotFoundException:
> org.thymeleaf.dialect.IProcessorDialect   at
> Java.net.URLClassLoader.findClass(URLClassLoader.Java:381)
> ~[na:1.8.0_60]    at
> Java.lang.ClassLoader.loadClass(ClassLoader.Java:424) ~[na:1.8.0_60]
>   at Sun.misc.Launcher$AppClassLoader.loadClass(Launcher.Java:331)
> ~[na:1.8.0_60]    at
> Java.lang.ClassLoader.loadClass(ClassLoader.Java:357) ~[na:1.8.0_60]
>   ... 56 common frames omitted
> 
> 2016-05-17 17:23:01.581  INFO 96267 --- [  restartedMain]
> .b.l.ClasspathLoggingApplicationListener : Application failed to start
> with classpath:
> [file:/Users/guillaume/dev/workspace/e-stored/target/classes/]
19

Merci pour le commentaire utile de M. Deinum!

Il apparaît en effet que la version 3.0.0 de "Thymeleaf Extras for Spring Security 4" n’est pas encore prise en charge.

J'ai changé la version de dépendance Maven de Thymeleaf thymeleaf-extras-springsecurity4 dans mon fichier POM de 3.0.0 à la dernière version 2.xx (2.1.2 au moment de cet article), et le problème a été résolu .

De: 

    <!-- http://mvnrepository.com/artifact/org.thymeleaf.extras/thymeleaf-extras-springsecurity4 -->
    <dependency>
        <groupId>org.thymeleaf.extras</groupId>
        <artifactId>thymeleaf-extras-springsecurity4</artifactId>
        <version>3.0.0.RELEASE</version>
    </dependency>

à:

    <!-- http://mvnrepository.com/artifact/org.thymeleaf.extras/thymeleaf-extras-springsecurity4 -->
    <dependency>
        <groupId>org.thymeleaf.extras</groupId>
        <artifactId>thymeleaf-extras-springsecurity4</artifactId>
        <version>2.1.2.RELEASE</version>
    </dependency>

Le problème n'apparaît plus, l'application Web démarre correctement et les balises sont reconnues :)

27

Cela me sauve la vie.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

Utiliser: Maven 3.5.0 
Java 1.8.0_152
Spring: https://start.spring.io -> Spring Boot :: (v2.0.0.BUILD-SNAPSHOT)

0
Stipan Beljan

Enfin, il fonctionne avec les configurations de démarrage à ressort par défaut comme suit - Version de démarrage à ressort 1.5.8.LELEASE

 <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.thymeleaf.extras</groupId>
         <artifactId>thymeleaf-extras-springsecurity4</artifactId>
    </dependency>

Cela va ajouter 

  • Thymeleaf-spring4 version 2.1.5.RELEASE
  • Vésrsion de thymeleaf 2.1.5.LELEASE 
  • Thymeleaf-extra-springsecurity4 version 2.1.3.RELEASE
  • Spring-security 4.2.3.LELEASE

    Assurez-vous d'ignorer la définition du bean SpringSecurityDialect dans le fichier de configuration, cela ne fonctionnera pas. utilisez simplement la valeur par défaut sauf si vous devez faire autre chose.

0
Hany Sakr