1. 程式人生 > >spring boot 整合redis+shiro在自定義Realm不能使用@Autowired註解

spring boot 整合redis+shiro在自定義Realm不能使用@Autowired註解

剛開始spring boot 整合shiro快取使用的是ehcache,自動注入userService如下,沒有問題

@Autowired
@Lazy
private SysUserService userService;

當將快取換成了redis後,該註解無效,一直空指標,大概是因為 Spring 載入順序等原因 解決方案是在自定義Realm中不直接使用@Autowired,而是將userService定義成成員變數,再

     private SysUserService userService;
        @Autowired
        private void setSysUserService
(SysUserService userService) { this.userService = userService; }

另外一個點就是SecurityManager的setRealm方法,不能直接new 自定義Realm,而是要以引數的形式傳入

 @Bean
    public SecurityManager securityManager(@Qualifier("myShiroRealm")MyShiroRealm myShiroRealm) {
        DefaultWebSecurityManager securityManager = new
DefaultWebSecurityManager(); // 設定realm. securityManager.setRealm(myShiroRealm); securityManager.setCacheManager(cacheManager()); securityManager.setSessionManager(sessionManager()); return securityManager; }

附完整ShiroConfig

package cn.com.suntree.cmp.config;

import
java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import lombok.extern.log4j.Log4j2; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.LockedAccountException; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.credential.CredentialsMatcher; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.realm.AuthorizingRealm; 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.subject.PrincipalCollection; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; 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.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; import cn.com.suntree.cmp.entity.Power; import cn.com.suntree.cmp.entity.Role; import cn.com.suntree.cmp.entity.SysUser; import cn.com.suntree.cmp.service.SysUserService; import javax.annotation.Resource; @Log4j2 @Configuration public class ShiroConfig { /** @Autowired @Lazy private SysUserService userService; */ /** * @param securityManager * @return 攔截工廠配置 */ @Bean public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); HashMap<String, String> filterMap = new LinkedHashMap<>(); filterMap.put("/api/city/page", "anon"); filterMap.put("/api/**", "authc"); //filterMap.put("/logout", "logout"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap); shiroFilterFactoryBean.setLoginUrl("/login"); shiroFilterFactoryBean.setUnauthorizedUrl("/error"); shiroFilterFactoryBean.setSecurityManager(securityManager); return shiroFilterFactoryBean; } /** * @return 安全管理器 */ @Bean public SecurityManager securityManager(@Qualifier("myShiroRealm") MyShiroRealm myShiroRealm) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 設定realm. securityManager.setRealm(myShiroRealm); // 自定義快取實現 使用redis securityManager.setCacheManager(cacheManager()); // 自定義session管理 使用redis securityManager.setSessionManager(sessionManager()); return securityManager; } /** * 身份認證realm; (這個需要自己寫,賬號密碼校驗;許可權等) * * @return */ @Bean public MyShiroRealm myShiroRealm() { MyShiroRealm myShiroRealm = new MyShiroRealm(); myShiroRealm.setCredentialsMatcher(credentialsMatcher()); myShiroRealm.setCacheManager(cacheManager());//設定快取 return myShiroRealm; } /** * cacheManager 快取 redis實現 * 使用的是shiro-redis開源外掛 * * @return */ public RedisCacheManager cacheManager() { RedisCacheManager redisCacheManager = new RedisCacheManager(); redisCacheManager.setRedisManager(redisManager()); return redisCacheManager; } /** * 配置shiro redisManager * 使用的是shiro-redis開源外掛 * * @return */ public RedisManager redisManager() { RedisManager redisManager = new RedisManager(); redisManager.setHost("localhost"); redisManager.setPort(6379); redisManager.setExpire(1800);// 配置快取過期時間 redisManager.setTimeout(0); // redisManager.setPassword(password); return redisManager; } /** * Session Manager * 使用的是shiro-redis開源外掛 */ @Bean public DefaultWebSessionManager sessionManager() { DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); sessionManager.setSessionDAO(redisSessionDAO()); return sessionManager; } /** * RedisSessionDAO shiro sessionDao層的實現 通過redis * 使用的是shiro-redis開源外掛 */ @Bean public RedisSessionDAO redisSessionDAO() { RedisSessionDAO redisSessionDAO = new RedisSessionDAO(); redisSessionDAO.setRedisManager(redisManager()); return redisSessionDAO; } /** * 限制同一賬號登入同時登入人數控制 * * @return */ @Bean public KickoutSessionControlFilter kickoutSessionControlFilter() { KickoutSessionControlFilter kickoutSessionControlFilter = new KickoutSessionControlFilter(); kickoutSessionControlFilter.setCacheManager(cacheManager()); kickoutSessionControlFilter.setSessionManager(sessionManager()); kickoutSessionControlFilter.setKickoutAfter(false); kickoutSessionControlFilter.setMaxSession(1); kickoutSessionControlFilter.setKickoutUrl("/auth/kickout"); return kickoutSessionControlFilter; } /*** * 授權所用配置 * * @return */ @Bean public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator(); defaultAAP.setProxyTargetClass(true); return defaultAAP; } /** * @param securityManager * @return 授權註解支援 */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } /** * Shiro生命週期處理器 */ @Bean public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } /** * @return 密碼匹配器 */ @Bean public CredentialsMatcher credentialsMatcher() { HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); hashedCredentialsMatcher.setHashAlgorithmName("md5"); return hashedCredentialsMatcher; } /** * 自定義 - 資料域 */ public class MyShiroRealm extends AuthorizingRealm { private SysUserService userService; @Autowired private void setSysUserService(SysUserService userService) { this.userService = userService; } /** * @param principalCollection * @return * @implNote 功能授權 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { SysUser user = (SysUser) principalCollection.getPrimaryPrincipal(); SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); user = userService.getUserInfoByUserId(user.getUserID()); List<Role> roleList = user.getRoleList(); for (Role role : roleList) { authorizationInfo.addRole(role.getRoleName()); for (Power permission : role.getPowerList()) { authorizationInfo.addStringPermission(permission.getUrl()); } } return authorizationInfo; } /** * @param authenticationToken * @return * @throws AuthenticationException * @implNote 身份認證 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { String acc = (String) authenticationToken.getPrincipal(); SysUser user = userService.getUserByAcc(acc); if (user == null) { throw new UnknownAccountException(); } else if ("0".equals(user.getIsLock())) { throw new LockedAccountException(); // 帳號凍結,非正常 } else { SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user, user.getPasswd(), this.getName()); return simpleAuthenticationInfo; } } } }