spring boot 整合redis+shiro在自定義Realm不能使用@Autowired註解
阿新 • • 發佈:2018-12-09
剛開始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;
}
}
}
}