SpringBoot导入Shiro很简单只需要导入shiro-spring-boot-starter
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-starter</artifactId> <version>1.5.2</version> </dependency> 复制代码
导入shiro-spring-boot-starter只需要很少的配置就能让Shiro工作 它有两个自动装配类 ShiroAutoConfiguration 自动配置一些Shiro相关的配置类 ShiroAnnotationProcessorAutoConfiguration 这个类可以让Shiro注解生效 例如:@RequiresAuthentication和RequiresPermissions
但是就是这个ShiroAnnotationProcessorAutoConfiguration会和Spring AOP起冲突
启动SpringBoot会出现这个错误
*************************** APPLICATION FAILED TO START *************************** Description: The bean 'xxxx' could not be injected as a 'com.xxx.xxx' because it is a JDK dynamic proxy that implements: com.egzosn.pay.common.api.PayMessageHandler Action: Consider injecting the bean as one of its interfaces or forcing the use of CGLib-based proxies by setting proxyTargetClass=true on @EnableAsync and/or @EnableCaching. 复制代码
这个时候你需要在SpringBootApplication排除ShiroAnnotationProcessorAutoConfiguration
@SpringBootApplication(exclude = {ShiroAnnotationProcessorAutoConfiguration.class}) 复制代码
这样就不会报错了,不过有些人在在自己的Shiro配置类(ShiroConfiguration)
加入了
@Bean @DependsOn("lifecycleBeanPostProcessor") public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); defaultAdvisorAutoProxyCreator.setProxyTargetClass(true); return defaultAdvisorAutoProxyCreator; } 复制代码
所以不排除ShiroAnnotationProcessorAutoConfiguration也不会报错,但是在这里配置的动态代理会导致Spring AOP失效 导致Spring AOP失效 会后果是你使用了@EnableCaching和@EnableAsync都失效,比如你在方法上使用@Async它还是会使用同一个线程,导致达不到异步执行的效果
@Configuration public class ShiroConfiguration { @Bean("securityManager") public DefaultWebSecurityManager getManager(JwtRealm realm) { DefaultWebSecurityManager manager = new DefaultWebSecurityManager(); // 使用自己的realm manager.setRealm(realm); /* * 关闭shiro自带的session,详情见文档 * http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29 */ DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO(); DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator(); // defaultSessionStorageEvaluator.setSessionStorageEnabled(false); subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator); manager.setSubjectDAO(subjectDAO); return manager; } @Bean("shiroFilter") public ShiroFilterFactoryBean factory(DefaultWebSecurityManager securityManager, AppProperties appProperties) { ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean(); // 添加自己的过滤器并且取名为jwt Map<String, Filter> filterMap= new HashMap<>(10); filterMap.put("jwt", new JwtTokenFilter()); factoryBean.setFilters(filterMap); factoryBean.setSecurityManager(securityManager); factoryBean.setUnauthorizedUrl("/401"); /* * 自定义url规则 * http://shiro.apache.org/web.html#urls- */ Map<String, String> filterRuleMap = new HashMap<>(10); // 所有请求通过我们自己的JWT Filter 全部放行 x.put("/**", "anon"); filterRuleMap.put("/**", "jwt"); if (appProperties != null && CollUtil.isNotEmpty(appProperties.getIgnoreingUrls())) { for (String ignoreingUrl : appProperties.getIgnoreingUrls()) { filterRuleMap.put(ignoreingUrl, "anon"); } } factoryBean.setFilterChainDefinitionMap(filterRuleMap); return factoryBean; } /** * 下面的代码是添加注解支持 */ // @Bean // @ConditionalOnClass // @DependsOn("lifecycleBeanPostProcessor") // public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { // DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); // defaultAdvisorAutoProxyCreator.setProxyTargetClass(true); // return defaultAdvisorAutoProxyCreator; // } // LifecycleBeanPostProcessor会导致Spring AOP失效 // @Bean // public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { // return new LifecycleBeanPostProcessor(); // } // @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) { AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(securityManager); return advisor; } } 复制代码
DefaultAdvisorAutoProxyCreator和LifecycleBeanPostProcessor我都注释了,这两个类会导致AOP失效
因为已经加入了Spring AOP所以不需要使用DefaultAdvisorAutoProxyCreator
我们只要在配置文件 application.properties 加入 spring.aop.proxy-target-class=true 然后在SpringBoot启动类注解排除 ShiroAnnotationProcessorAutoConfiguration
@SpringBootApplication(exclude = {ShiroAnnotationProcessorAutoConfiguration.class}) 复制代码
这样SPring AOP就正常了,Shiro注册也可以使用了.
@Bean @DependsOn({"lifecycleBeanPostProcessor"}) @ConditionalOnMissingBean public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { return super.defaultAdvisorAutoProxyCreator(); } 复制代码
加入DefaultAdvisorAutoProxyCreator会导致Spring AOP失效,所有@Service @Component的类都不是动态代理对象 导致@Aysnc和@Cacheable等注解的失效
@Bean @ConditionalOnClass @DependsOn("lifecycleBeanPostProcessor") public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); defaultAdvisorAutoProxyCreator.setProxyTargetClass(true); } @Bean public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } 复制代码
LifecycleBeanPostProcessor 和 DefaultAdvisorAutoProxyCreator都会导致Spring AOP失效, 如果你想让Shiro注解生效加入AuthorizationAttributeSourceAdvisor类和spring配置spring.aop.proxy-target-class=true