【Shiro】Unsatisfied dependency expressed through method 'securityManager' parameter 3
大家好,我是烤鸭:
采坑记录,springboot 整合 shiro。
环境:
springboot 2.0.5.RELEASE
shiro-spring 1.4.0
shiro-redis 3.1.0
1.问题
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'shiroFilter' defined in class path resource [com/test/shiro/ShiroConfig.class]: Unsatisfied dependency expressed through method 'shiroFilter' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name'securityManager' defined in class path resource [com/test/shiro/ShiroConfig.class]: Unsatisfied dependency expressed through method 'securityManager' parameter 3; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.crazycake.shiro.RedisCacheManager' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
2.原因
按异常信息去百度查结果,效果不理想。同事本地试过是没有问题的,合代码的时候出现了问题。争取少改动代码解决问题。
发现不太好改,找不到问题在哪。
代码重现。主要是
ShiroConfig.java
package com.test.shiro;import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.RememberMeManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.Cookie;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;@Slf4j
public class ShiroConfig {@Value("${spring.redis.host}")private String redisHost;@Value("${spring.redis.port}")private Integer redisPort;/*@Value("${spring.redis.password}")private String redisPassword;*/@Value("${spring.redis.timeout}")private Integer redisTimeout;@Beanpublic ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();//设置安全管理器shiroFilterFactoryBean.setSecurityManager(securityManager);//默认跳转到登陆页面shiroFilterFactoryBean.setLoginUrl("/test/web/sysUser/noLogin");//登陆成功后的页面shiroFilterFactoryBean.setSuccessUrl("/test/web/sysUser/loginSuccess");shiroFilterFactoryBean.setUnauthorizedUrl("/403");//自定义过滤器Map<String, Filter> filterMap = new LinkedHashMap<>();shiroFilterFactoryBean.setFilters(filterMap);// 权限控制mapMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();// 配置不会被拦截的链接 顺序判断// 配置登录方法不被拦截filterChainDefinitionMap.put("/web/login", "anon");filterChainDefinitionMap.put("/test/web/login", "anon");filterChainDefinitionMap.put("/test/web/sysUser/login", "anon");filterChainDefinitionMap.put("/web/sysUser/login", "anon");filterChainDefinitionMap.put("/test/web/sysUser/code", "anon");filterChainDefinitionMap.put("/test/web/sysUser/verification/code", "anon");filterChainDefinitionMap.put("/test/web/sysUser/addSysUser", "anon");// 配置APP接口不被拦截filterChainDefinitionMap.put("/test/app/**", "anon");// 配置静态页面不被拦截
// filterChainDefinitionMap.put("/static/**", "anon");// 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了filterChainDefinitionMap.put("/logout", "logout");// 过滤链定义,从上向下顺序执行,一般将/**放在最为下边。// authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问filterChainDefinitionMap.put("/**", "authc"); // 拦截所有链接shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);return shiroFilterFactoryBean;}/*** 核心的安全事务管理器* 设置realm、cacheManager等*/@Bean(name = "securityManager")public SecurityManager securityManager(ShiroRealm shiroRealm, SessionManager sessionManager, RememberMeManager rememberMeManager, RedisCacheManager cacheManager){DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();// 设置 RealmsecurityManager.setRealm(shiroRealm);// 记住密码管理器securityManager.setRememberMeManager(rememberMeManager);// 自定义session管理 使用redissecurityManager.setSessionManager(sessionManager);// 自定义缓存实现 使用redissecurityManager.stestacheManager(cacheManager);return securityManager;}/*** Session的管理*/@Bean(name = "sessionManager")public DefaultWebSessionManager sessionManager(RedisSessionDAO redisSessionDAO) {DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();sessionManager.setSessionDAO(redisSessionDAO);// 设置session过期时间为1小时(单位:毫秒),默认为30分钟sessionManager.setGlobalSessionTimeout(60 * 60 * 1000);sessionManager.setSessionValidationSchedulerEnabled(true);return sessionManager;}/*** 身份认证Realm,此处的注入不可以缺少。否则会在UserRealm中注入对象会报空指针.*/@Bean(name = "shiroRealm")public ShiroRealm shiroRealm(HashedCredentialsMatcher hashedCredentialsMatcher){ShiroRealm myShiroRealm = new ShiroRealm();myShiroRealm.stestredentialsMatcher(hashedCredentialsMatcher);return myShiroRealm;}/*** 哈希密码比较器。在ShiroRealm中作用参数使用* 登陆时会比较用户输入的密码,跟数据库密码配合盐值salt解密后是否一致。*/@Bean(name = "hashedCredentialsMatcher")public HashedCredentialsMatcher hashedCredentialsMatcher(){HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();hashedCredentialsMatcher.setHashAlgorithmName("md5"); //散列算法:这里使用md5算法;hashedCredentialsMatcher.setHashIterations(2); //散列的次数,比如散列两次,相当于 md5(md5(""));return hashedCredentialsMatcher;}/*** 配置自定义的密码比较器*/@Bean(name = "credentialsMatcher")public CredentialsMatcher credentialsMatcher(){return new CredentialsMatcher();}/*** 配置shiro redisManager* 使用的是shiro-redis开源插件*/@Bean(name = "redisManager")public RedisManager redisManager() {RedisManager redisManager = new RedisManager();redisManager.setHost(redisHost);redisManager.setPort(redisPort);// redisManager.setPassword(redisPassword);//redisManager.setExpire(1800); // 配置缓存过期时间redisManager.setTimeout(redisTimeout);return redisManager;}/*** cacheManager 缓存 redis实现* 使用的是shiro-redis开源插件*/@Bean(name = "cacheManager")public RedisCacheManager cacheManager(RedisManager redisManager) {RedisCacheManager redisCacheManager = new RedisCacheManager();redisCacheManager.setRedisManager(redisManager);//redisCacheManager.getRedisManager()return redisCacheManager;}/*** RedisSessionDAO shiro sessionDao层的实现 通过redis* 使用的是shiro-redis开源插件*/@Bean(name = "redisSessionDAO")public RedisSessionDAO redisSessionDAO(RedisManager redisManager) {RedisSessionDAO redisSessionDAO = new RedisSessionDAO();redisSessionDAO.setRedisManager(redisManager);return redisSessionDAO;}/*** 记住我管理器*/@Bean(name = "rememberMeManager")public CookieRememberMeManager rememberMeManager(Cookie rememberMeCookie) {CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();cookieRememberMeManager.stestookie(rememberMeCookie);// rememberMe cookie加密的密钥 默认AES算法
// cookieRememberMeManager.stestipherKey();return cookieRememberMeManager;}/*** cookie对象*/@Bean(name = "rememberMeCookie")public Cookie rememberMeCookie() {SimpleCookie simpleCookie = new SimpleCookie("rememberMe");// 记住我cookie生效时间,单位:秒simpleCookie.setMaxAge(3600);return simpleCookie;}/*** 开启shiro aop注解支持.* 使用代理方式;所以需要开启代码支持;否则@RequiresRoles等注解无法生效*/@Beanpublic AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);return authorizationAttributeSourceAdvisor;}/*** Shiro生命周期处理器*/@Beanpublic static LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){return new LifecycleBeanPostProcessor();}/*** 自动创建代理*/@Bean@DependsOn({"lifecycleBeanPostProcessor"})public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();advisorAutoProxyCreator.setProxyTargtestlass(true);return advisorAutoProxyCreator;}
}
根据报错信息和上面的代码找问题。异常都是从下往上看的。
源头:
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.crazycake.shiro.RedisCacheManager' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
RedisCacheManager 没注入,所以用到的地方会报错。
用到的地方是 securityManager(ShiroRealm shiroRealm, SessionManager sessionManager, RememberMeManager rememberMeManager, RedisCacheManager cacheManager) 构造方法的第三个参数
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'securityManager' defined in class path resource [com/test/shiro/ShiroConfig.class]: Unsatisfied dependency expressed through method 'securityManager' parameter 3。
问题找到就好解决了。
改写构造方法。改后的shiroConfig.java如下。
package com.etc.shiro;import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.Cookie;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;@Slf4j
@Configuration
public class ShiroConfig {@Value("${spring.redis.host}")private String redisHost;@Value("${spring.redis.port}")private Integer redisPort;@Value("${spring.redis.password}")private String redisPassword;@Value("${spring.redis.timeout}")private Integer redisTimeout;@Beanpublic ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();//自定义过滤器Map<String, Filter> filterMap = new LinkedHashMap<>();shiroFilterFactoryBean.setFilters(filterMap);// 权限控制mapLinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();// 配置不会被拦截的链接 顺序判断// 配置登录方法不被拦截filterChainDefinitionMap.put("/invoke/*", "anon");filterChainDefinitionMap.put("/web/login", "anon");filterChainDefinitionMap.put("/etc/web/login", "anon");filterChainDefinitionMap.put("/etc/web/sysUser/login", "anon");filterChainDefinitionMap.put("/web/sysUser/login", "anon");filterChainDefinitionMap.put("/web/sysUser/getcode", "anon");filterChainDefinitionMap.put("/etc/web/sysUser/verification/code", "anon");filterChainDefinitionMap.put("/etc/web/sysUser/addSysUser", "anon");// 配置APP接口不被拦截filterChainDefinitionMap.put("/etc/app/**", "anon");// 配置静态页面不被拦截filterChainDefinitionMap.put("/static/**", "anon");// 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了filterChainDefinitionMap.put("/logout", "logout");// 过滤链定义,从上向下顺序执行,一般将/**放在最为下边。// authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问//· filterChainDefinitionMap.put("/**", "authc"); // 拦截所有链接shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);//设置安全管理器shiroFilterFactoryBean.setSecurityManager(securityManager);//默认跳转到登陆页面shiroFilterFactoryBean.setLoginUrl("/etc/web/sysUser/noLogin");//登陆成功后的页面shiroFilterFactoryBean.setSuccessUrl("/etc/web/sysUser/loginSuccess");shiroFilterFactoryBean.setUnauthorizedUrl("/403");return shiroFilterFactoryBean;}/*** 核心的安全事务管理器* 设置realm、cacheManager等*/@Beanpublic SecurityManager securityManager(ShiroRealm shiroRealm){DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();// 设置 RealmsecurityManager.setRealm(shiroRealm);// 记住密码管理器securityManager.setRememberMeManager(rememberMeManager());// 自定义session管理 使用redissecurityManager.setSessionManager(sessionManager());// 自定义缓存实现 使用redissecurityManager.setCacheManager(redisCacheManager());return securityManager;}/*** Session的管理*/@Bean(name = "sessionManager")public DefaultWebSessionManager sessionManager() {DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();sessionManager.setSessionDAO(redisSessionDAO());// 设置session过期时间为1小时(单位:毫秒),默认为30分钟sessionManager.setGlobalSessionTimeout(60 * 60 * 1000);sessionManager.setSessionValidationSchedulerEnabled(true);return sessionManager;}/*** 身份认证Realm,此处的注入不可以缺少。否则会在UserRealm中注入对象会报空指针.*/@Beanpublic ShiroRealm shiroRealm(){ShiroRealm myShiroRealm = new ShiroRealm();myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());return myShiroRealm;}/*** 哈希密码比较器。在ShiroRealm中作用参数使用* 登陆时会比较用户输入的密码,跟数据库密码配合盐值salt解密后是否一致。*/@Bean(name = "hashedCredentialsMatcher")public HashedCredentialsMatcher hashedCredentialsMatcher(){HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();hashedCredentialsMatcher.setHashAlgorithmName("md5"); //散列算法:这里使用md5算法;hashedCredentialsMatcher.setHashIterations(2); //散列的次数,比如散列两次,相当于 md5(md5(""));return hashedCredentialsMatcher;}/*** 配置自定义的密码比较器*/@Bean(name = "credentialsMatcher")public CredentialsMatcher credentialsMatcher(){return new CredentialsMatcher();}// /**
// * Shiro 缓存管理器
// * 需要注入对应的其它的实体类中: 安全管理器:securityManager
// * 可见securityManager是整个shiro的核心;
// */
// @Bean
// public EhCacheManager ehCacheManager(){
// logger.info("------------->ShiroConfiguration.getEhCacheManager()执行");
// EhCacheManager cacheManager = new EhCacheManager();
// cacheManager.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");
// return cacheManager;
// }/*** 配置shiro redisManager* 使用的是shiro-redis开源插件*/@Bean(name = "redisManager")public RedisManager redisManager() {RedisManager redisManager = new RedisManager();redisManager.setHost(redisHost);redisManager.setPort(redisPort);redisManager.setPassword(redisPassword);//redisManager.setExpire(1800); // 配置缓存过期时间redisManager.setTimeout(redisTimeout);return redisManager;}/*** cacheManager 缓存 redis实现* 使用的是shiro-redis开源插件*/@Beanpublic RedisCacheManager redisCacheManager() {RedisCacheManager redisCacheManager = new RedisCacheManager();redisCacheManager.setRedisManager(redisManager());return redisCacheManager;}/*** RedisSessionDAO shiro sessionDao层的实现 通过redis* 使用的是shiro-redis开源插件*/@Beanpublic RedisSessionDAO redisSessionDAO() {RedisSessionDAO redisSessionDAO = new RedisSessionDAO();redisSessionDAO.setRedisManager(redisManager());return redisSessionDAO;}/*** 记住我管理器*/@Beanpublic CookieRememberMeManager rememberMeManager() {CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();cookieRememberMeManager.setCookie(rememberMeCookie());// rememberMe cookie加密的密钥 默认AES算法
// cookieRememberMeManager.setCipherKey();return cookieRememberMeManager;}/*** cookie对象*/@Beanpublic Cookie rememberMeCookie() {SimpleCookie simpleCookie = new SimpleCookie("rememberMe");// 记住我cookie生效时间,单位:秒simpleCookie.setMaxAge(3600);return simpleCookie;}/*** 开启shiro aop注解支持.* 使用代理方式;所以需要开启代码支持;否则@RequiresRoles等注解无法生效*/@Beanpublic AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);return authorizationAttributeSourceAdvisor;}/*** Shiro生命周期处理器*/@Beanpublic static LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){return new LifecycleBeanPostProcessor();}/*** 自动创建代理*/@Bean@DependsOn({"lifecycleBeanPostProcessor"})public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();advisorAutoProxyCreator.setProxyTargetClass(true);return advisorAutoProxyCreator;}
}
遇到问题时,没有搜索到特别好的解决方式时。
并没有根据报错信息仔细查找问题源头(主要也是因为看不懂),应该优先分析报错信息,这样会解决的比较快。
【Shiro】Unsatisfied dependency expressed through method 'securityManager' parameter 3相关推荐
- Unsatisfied dependency expressed through method ‘redisTemplate‘ parameter 0;
原因分析: Error starting ApplicationContext. To display the auto-configuration report re-run your applic ...
- SpringBoot多数据源unsatisfied dependency expressed through method 'entityManagerFactoryBuilder...
本来的项目(基于SpringBoot 2.0.5-RELEASE)集成了JPA.mybatis的注解.XML方式访问DB. 后面集成多数据源的时候启动SpringBoot时出现了如下错误: ERROR ...
- sping boot集成多数据源的时候会出现 unsatisfied dependency expressed through method
因为springboot首推的连接池使用了HikariCP连接池,GET到这个点, HikariDataSource的获取数据库连接的getConnection方法 修改application.pro ...
- 关于SpringCloud报错Unsatisfied dependency expressed through field ‘propertySourceLocators的解决之一
这里写目录标题 1. 问题简述 2. 报错显示 3. 问题说明 1. 问题简述 今天给大家看一下,关于SpringCloud报错,Unsatisfied dependency expressed th ...
- 【错误记录】Error creating bean with name: Unsatisfied dependency expressed through field
启动一个Spring boot集成mybatis plus报错: Error creating bean with name 'examManageController': Unsatisfied d ...
- spring异常Unsatisfied dependency expressed through constructor parameter 0
异常信息: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with nam ...
- Unsatisfied dependency expressed through field 'service'
启动SpringBoot项目报以下错误 Error starting ApplicationContext. To display the conditions report re-run your ...
- Error creating bean with name ,Unsatisfied dependency expressed through field
今天打开idea发现项目跑不起来了,一直报这个错 org.springframework.beans.factory.UnsatisfiedDependencyException: Error cre ...
- Unsatisfied dependency expressed through field 'baseMapper'
今天项目 springboot 1.* 升级到 2.0.4,以至于将 Mybatis-Plus 升级,springBoot 启动之后报错Unsatisfied dependency expressed ...
最新文章
- sql floor 取整函数
- linux 内存显示括号内字母的含义
- 直接点不玩虚的--启明云端千元现金红包、50pcs开发板直播现场拿走不谢
- 管理员密码的php文件,ecshop网站后台管理员密码找回办法
- ​ RROR 1221 (HY000): Incorrect usage of spatial/fulltext/hash index and explicit index orde ​
- ADO.NET数据库
- java.lang.NoSuchMethodError: javax.servlet.http.HttpServletRequest.isAsyncStarted()Z 的解决
- 《深入理解 Spring Cloud 与微服务构建》第十二章 服务注册和发现 Consul
- script标签async和defer的区别及作用
- js如何保证iframe里的内容,显示在父窗口
- QT5之MYSQL操作
- [转载] Python3 String模块ascii_letters和digits
- 索尼音乐牵手UNLEASH厂牌 实力新星LiCong李聪 Veegee正式加盟
- python 反弹shell,加了UDP
- 小D课堂 - 新版本微服务springcloud+Docker教程_4-01 常用的服务间调用方式讲解
- 对于网络文学而言 计算机叙事,90年代文学的“增量”
- 基于随机效应贝叶斯神经网络(RE-BNN)的多区域出行模式选择分析
- 总结中间方攻击和CA认证中心
- 使用python连接clickhouse并发送邮件
- 移动、电信、联通、QQ币、游戏点卡快速秒充体验
热门文章
- 前端学习(3118):react-hello-react的解决类中方法的this
- [css] 使用css实现气泡框的效果
- [css] 如何形成BFC?
- 工作250:uniapp--实战--flex布局--星级评分
- 前端学习(2745):重读vue电商网站55之使用 pm2 管理应用
- 前端学习(2731):重读vue电商网站41之自定义格式化时间的全局过滤器
- 前端学习(2531):Vuex中getter
- spring学习(25):通过构造函数依赖注入
- java面试题3 牛客:下面有关jdbc statement的说法错误的是
- php金额类,PHP类-人民币金额转大写