我正在尝试将Thymeleaf安全方言(例如 sec:authorize 标签)集成到运行正常的Spring Boot + Spring Security应用程序中。
经过一番研究,我发现激活该问题的解决方案是:
在POM文件中添加依赖项:
<dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-springsecurity4</artifactId> <version>3.0.0.RELEASE</version> </dependency>
并在模板文件顶部添加标签:
<html xmlns:th="http://www.thymeleaf.org" lang="en" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
到目前为止,一切都很好。找到依赖关系,在标记中识别出标签。
但是,它们并未考虑在内,并出现在最终生成的HTML中。
由于无法启用Spring Boot自动配置中的问题,因此似乎有必要将 SpringSecurityDialect Bean 手动添加到一个@Configuration类中以启用它(在StackOverflow上找到的几个问题已通过此方法解决):
@Bean public SpringSecurityDialect securityDialect() { return new SpringSecurityDialect(); }
这就是导致问题的原因:当我将此Bean添加到我的Spring Boot Configuration中时,它会引发一个异常,因为它找不到类 org.thymeleaf.dialect.IProcessorDialect 。这是错误:
> 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)
我想念什么? 这是Thymeleaf的错误吗?Spring靴?我自己的代码?在此先感谢您的帮助 !
这是我的问题所涉及的一些文件:
应用程序
@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(); } }
胸腺模板:
<!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> ....
启动应用程序时的完整控制台输出:
> :: 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/]
感谢Deinum先生的有用评论!
确实确实不支持“ Spring Security 4的Thymeleaf Extras”版本3.0.0。
我已经将POM文件中Thymeleaf thymeleaf-extras-springsecurity4 的Maven依赖版本从3.0.0更改为最新的2.xx版本(在本文发布时为2.1.2),并且此问题已解决。
从:
<!-- 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>
问题不再出现,Web应用程序正常启动,并且可以识别标签:)