大家好,我是烤鸭:

采坑记录,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相关推荐

  1. Unsatisfied dependency expressed through method ‘redisTemplate‘ parameter 0;

    原因分析: Error starting ApplicationContext. To display the auto-configuration report re-run your applic ...

  2. SpringBoot多数据源unsatisfied dependency expressed through method 'entityManagerFactoryBuilder...

    本来的项目(基于SpringBoot 2.0.5-RELEASE)集成了JPA.mybatis的注解.XML方式访问DB. 后面集成多数据源的时候启动SpringBoot时出现了如下错误: ERROR ...

  3. sping boot集成多数据源的时候会出现 unsatisfied dependency expressed through method

    因为springboot首推的连接池使用了HikariCP连接池,GET到这个点, HikariDataSource的获取数据库连接的getConnection方法 修改application.pro ...

  4. 关于SpringCloud报错Unsatisfied dependency expressed through field ‘propertySourceLocators的解决之一

    这里写目录标题 1. 问题简述 2. 报错显示 3. 问题说明 1. 问题简述 今天给大家看一下,关于SpringCloud报错,Unsatisfied dependency expressed th ...

  5. 【错误记录】Error creating bean with name: Unsatisfied dependency expressed through field

    启动一个Spring boot集成mybatis plus报错: Error creating bean with name 'examManageController': Unsatisfied d ...

  6. spring异常Unsatisfied dependency expressed through constructor parameter 0

    异常信息: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with nam ...

  7. Unsatisfied dependency expressed through field 'service'

    启动SpringBoot项目报以下错误 Error starting ApplicationContext. To display the conditions report re-run your ...

  8. Error creating bean with name ,Unsatisfied dependency expressed through field

    今天打开idea发现项目跑不起来了,一直报这个错 org.springframework.beans.factory.UnsatisfiedDependencyException: Error cre ...

  9. Unsatisfied dependency expressed through field 'baseMapper'

    今天项目 springboot 1.* 升级到 2.0.4,以至于将 Mybatis-Plus 升级,springBoot 启动之后报错Unsatisfied dependency expressed ...

最新文章

  1. sql floor 取整函数
  2. linux 内存显示括号内字母的含义
  3. 直接点不玩虚的--启明云端千元现金红包、50pcs开发板直播现场拿走不谢
  4. 管理员密码的php文件,ecshop网站后台管理员密码找回办法
  5. ​ RROR 1221 (HY000): Incorrect usage of spatial/fulltext/hash index and explicit index orde ​
  6. ADO.NET数据库
  7. java.lang.NoSuchMethodError: javax.servlet.http.HttpServletRequest.isAsyncStarted()Z 的解决
  8. 《深入理解 Spring Cloud 与微服务构建》第十二章 服务注册和发现 Consul
  9. script标签async和defer的区别及作用
  10. js如何保证iframe里的内容,显示在父窗口
  11. QT5之MYSQL操作
  12. [转载] Python3 String模块ascii_letters和digits
  13. 索尼音乐牵手UNLEASH厂牌 实力新星LiCong李聪 Veegee正式加盟
  14. python 反弹shell,加了UDP
  15. 小D课堂 - 新版本微服务springcloud+Docker教程_4-01 常用的服务间调用方式讲解
  16. 对于网络文学而言 计算机叙事,90年代文学的“增量”
  17. 基于随机效应贝叶斯神经网络(RE-BNN)的多区域出行模式选择分析
  18. 总结中间方攻击和CA认证中心
  19. 使用python连接clickhouse并发送邮件
  20. 移动、电信、联通、QQ币、游戏点卡快速秒充体验

热门文章

  1. 前端学习(3118):react-hello-react的解决类中方法的this
  2. [css] 使用css实现气泡框的效果
  3. [css] 如何形成BFC?
  4. 工作250:uniapp--实战--flex布局--星级评分
  5. 前端学习(2745):重读vue电商网站55之使用 pm2 管理应用
  6. 前端学习(2731):重读vue电商网站41之自定义格式化时间的全局过滤器
  7. 前端学习(2531):Vuex中getter
  8. spring学习(25):通过构造函数依赖注入
  9. java面试题3 牛客:下面有关jdbc statement的说法错误的是
  10. php金额类,PHP类-人民币金额转大写