shiro中原始的RedisSessionDAO如下,keyPrefix为shiro_redis_session:,某些情况下需要自定义这个值
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package org.crazycake.shiro; import java.io.Serializable; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import org.apache.shiro.session.Session; import org.apache.shiro.session.UnknownSessionException; import org.apache.shiro.session.mgt.eis.AbstractSessionDAO; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class RedisSessionDAO extends AbstractSessionDAO { private static Logger logger = LoggerFactory.getLogger(RedisSessionDAO.class); private RedisManager redisManager; private String keyPrefix = "shiro_redis_session:"; public RedisSessionDAO() { } public void update(Session session) throws UnknownSessionException { this.saveSession(session); } private void saveSession(Session session) throws UnknownSessionException { if (session != null && session.getId() != null) { byte[] key = this.getByteKey(session.getId()); byte[] value = SerializeUtils.serialize(session); session.setTimeout((long)(this.redisManager.getExpire() * 1000)); this.redisManager.set(key, value, this.redisManager.getExpire()); } else { logger.error("session or session id is null"); } } public void delete(Session session) { if (session != null && session.getId() != null) { this.redisManager.del(this.getByteKey(session.getId())); } else { logger.error("session or session id is null"); } } public Collection<Session> getActiveSessions() { Set<Session> sessions = new HashSet(); Set<byte[]> keys = this.redisManager.keys(this.keyPrefix + "*"); if (keys != null && keys.size() > 0) { Iterator i$ = keys.iterator(); while(i$.hasNext()) { byte[] key = (byte[])i$.next(); Session s = (Session)SerializeUtils.deserialize(this.redisManager.get(key)); sessions.add(s); } } return sessions; } protected Serializable doCreate(Session session) { Serializable sessionId = this.generateSessionId(session); this.assignSessionId(session, sessionId); this.saveSession(session); return sessionId; } protected Session doReadSession(Serializable sessionId) { if (sessionId == null) { logger.error("session id is null"); return null; } else { Session s = (Session)SerializeUtils.deserialize(this.redisManager.get(this.getByteKey(sessionId))); return s; } } private byte[] getByteKey(Serializable sessionId) { String preKey = this.keyPrefix + sessionId; return preKey.getBytes(); } public RedisManager getRedisManager() { return this.redisManager; } public void setRedisManager(RedisManager redisManager) { this.redisManager = redisManager; this.redisManager.init(); } public String getKeyPrefix() { return this.keyPrefix; } public void setKeyPrefix(String keyPrefix) { this.keyPrefix = keyPrefix; } }
自定义:
public class MyRedisSessionDAO extends RedisSessionDAO { private Logger logger = LoggerFactory.getLogger(MyRedisSessionDAO.class); private RedisManager redisManager; //自定义key前缀 private String keyPrefix = "cmp_shiro_redis_session:"; public MyRedisSessionDAO() { } public void update(Session session) throws UnknownSessionException { this.saveSession(session); } private void saveSession(Session session) throws UnknownSessionException { if (session != null && session.getId() != null) { byte[] key = this.getByteKey(session.getId()); byte[] value = SerializeUtils.serialize(session); session.setTimeout((long)(this.redisManager.getExpire() * 1000)); this.redisManager.set(key, value, this.redisManager.getExpire()); } else { logger.error("session or session id is null"); } } public void delete(Session session) { if (session != null && session.getId() != null) { this.redisManager.del(this.getByteKey(session.getId())); } else { logger.error("session or session id is null"); } } public Collection<Session> getActiveSessions() { Set<Session> sessions = new HashSet(); Set<byte[]> keys = this.redisManager.keys(this.keyPrefix + "*"); if (keys != null && keys.size() > 0) { Iterator i$ = keys.iterator(); while(i$.hasNext()) { byte[] key = (byte[])i$.next(); Session s = (Session)SerializeUtils.deserialize(this.redisManager.get(key)); sessions.add(s); } } return sessions; } protected Serializable doCreate(Session session) { Serializable sessionId = this.generateSessionId(session); this.assignSessionId(session, sessionId); this.saveSession(session); return sessionId; } protected Session doReadSession(Serializable sessionId) { if (sessionId == null) { logger.error("session id is null"); return null; } else { Session s = (Session) SerializeUtils.deserialize(this.redisManager.get(this.getByteKey(sessionId))); return s; } } private byte[] getByteKey(Serializable sessionId) { String preKey = this.keyPrefix + sessionId; return preKey.getBytes(); } public RedisManager getRedisManager() { return this.redisManager; } public void setRedisManager(RedisManager redisManager) { this.redisManager = redisManager; this.redisManager.init(); } public String getKeyPrefix() { return this.keyPrefix; } public void setKeyPrefix(String keyPrefix) { this.keyPrefix = keyPrefix; } }
然后在DefaultWebSessionManager中
/** * Session Manager * 使用的是shiro-redis开源插件 */ @Bean public DefaultWebSessionManager sessionManager() { DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); sessionManager.setSessionDAO(redisSessionDAO()); return sessionManager; }
redisSessionDAO()的实现
@Bean public MyRedisSessionDAO redisSessionDAO() { MyRedisSessionDAO redisSessionDAO = new MyRedisSessionDAO(); redisSessionDAO.setRedisManager(redisManager()); return redisSessionDAO; }
附上完整的ShiroConfig代码
package cn.com.suntree.cmp.config; 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.CmpUserService; import cn.com.suntree.cmp.utils.CommonUtil; import cn.com.suntree.cmp.utils.YAMLUtils; import lombok.extern.log4j.Log4j2; import org.apache.shiro.authc.*; 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.session.Session; import org.apache.shiro.session.UnknownSessionException; 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.crazycake.shiro.SerializeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; import javax.servlet.Filter; import java.io.Serializable; import java.util.*; @Log4j2 @Configuration public class ShiroConfig { /** * @Autowired * @Lazy private SysUserService userService; */ @Autowired YAMLUtils yaml; /** * @param securityManager * @return 拦截工厂配置 */ @Bean public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // 必须设置 SecurityManager shiroFilterFactoryBean.setSecurityManager(securityManager); //自定义拦截器 Map<String, Filter> filtersMap = new LinkedHashMap<String, Filter>(); //限制同一帐号同时在线的个数。 filtersMap.put("kickout", kickoutSessionControlFilter()); shiroFilterFactoryBean.setFilters(filtersMap); //权限控制map HashMap<String, String> filterMap = new LinkedHashMap<>(); filterMap.put("/api/enclosure/download", "anon"); filterMap.put("/api/register/**", "anon"); filterMap.put("/api/enclosure/onlinePreview", "anon"); filterMap.put("/api/**", "authc"); shiroFilterFactoryBean.setLoginUrl("/login"); shiroFilterFactoryBean.setUnauthorizedUrl("/error"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap); 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(yaml.redis_host); redisManager.setPort(yaml.redis_port); redisManager.setExpire(yaml.redis_cache);// 配置缓存过期时间 redisManager.setTimeout(0); redisManager.setPassword(yaml.redis_passwd); return redisManager; } /** * Session Manager * 使用的是shiro-redis开源插件 */ @Bean public DefaultWebSessionManager sessionManager() { DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); sessionManager.setSessionDAO(redisSessionDAO()); return sessionManager; } public class MyRedisSessionDAO extends RedisSessionDAO { private Logger logger = LoggerFactory.getLogger(MyRedisSessionDAO.class); private RedisManager redisManager; private String keyPrefix = "cmp_shiro_redis_session:"; public MyRedisSessionDAO() { } public void update(Session session) throws UnknownSessionException { this.saveSession(session); } private void saveSession(Session session) throws UnknownSessionException { if (session != null && session.getId() != null) { byte[] key = this.getByteKey(session.getId()); byte[] value = SerializeUtils.serialize(session); session.setTimeout((long)(this.redisManager.getExpire() * 1000)); this.redisManager.set(key, value, this.redisManager.getExpire()); } else { logger.error("session or session id is null"); } } public void delete(Session session) { if (session != null && session.getId() != null) { this.redisManager.del(this.getByteKey(session.getId())); } else { logger.error("session or session id is null"); } } public Collection<Session> getActiveSessions() { Set<Session> sessions = new HashSet(); Set<byte[]> keys = this.redisManager.keys(this.keyPrefix + "*"); if (keys != null && keys.size() > 0) { Iterator i$ = keys.iterator(); while(i$.hasNext()) { byte[] key = (byte[])i$.next(); Session s = (Session)SerializeUtils.deserialize(this.redisManager.get(key)); sessions.add(s); } } return sessions; } protected Serializable doCreate(Session session) { Serializable sessionId = this.generateSessionId(session); this.assignSessionId(session, sessionId); this.saveSession(session); return sessionId; } protected Session doReadSession(Serializable sessionId) { if (sessionId == null) { logger.error("session id is null"); return null; } else { Session s = (Session) SerializeUtils.deserialize(this.redisManager.get(this.getByteKey(sessionId))); return s; } } private byte[] getByteKey(Serializable sessionId) { String preKey = this.keyPrefix + sessionId; return preKey.getBytes(); } public RedisManager getRedisManager() { return this.redisManager; } public void setRedisManager(RedisManager redisManager) { this.redisManager = redisManager; this.redisManager.init(); } public String getKeyPrefix() { return this.keyPrefix; } public void setKeyPrefix(String keyPrefix) { this.keyPrefix = keyPrefix; } } /** * RedisSessionDAO shiro sessionDao层的实现 通过redis * 使用的是shiro-redis开源插件 */ @Bean public MyRedisSessionDAO redisSessionDAO() { MyRedisSessionDAO redisSessionDAO = new MyRedisSessionDAO(); //自定义sessionId生成器 //redisSessionDAO.setSessionIdGenerator(mySessionIdGenerstor()); redisSessionDAO.setRedisManager(redisManager()); return redisSessionDAO; } /* @Bean public MySessionIdGenerstor mySessionIdGenerstor(){ return new MySessionIdGenerstor(); } */ /** * 限制同一账号登录同时登录人数控制 * * @return */ @Bean public KickoutSessionControlFilter kickoutSessionControlFilter() { KickoutSessionControlFilter kickoutSessionControlFilter = new KickoutSessionControlFilter(); //使用cacheManager获取相应的cache来缓存用户登录的会话;用于保存用户—会话之间的关系的; //这里我们还是用之前shiro使用的redisManager()实现的cacheManager()缓存管理 //也可以重新另写一个,重新配置缓存时间之类的自定义缓存属性 kickoutSessionControlFilter.setCacheManager(cacheManager()); //用于根据会话ID,获取会话进行踢出操作的; kickoutSessionControlFilter.setSessionManager(sessionManager()); //是否踢出后来登录的,默认是false;即后者登录的用户踢出前者登录的用户;踢出顺序。 kickoutSessionControlFilter.setKickoutAfter(false); //同一个用户最大的会话数,默认1;比如2的意思是同一个用户允许最多同时两个人登录; kickoutSessionControlFilter.setMaxSession(1); //被踢出后重定向到的地址; kickoutSessionControlFilter.setKickoutUrl("/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 { @Autowired @Lazy private CmpUserService userService; //@Autowired //private void setSysUserService(CmpUserService 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()); user = userService.getUserDetailInfoByUserId(user.getUserID(), user.getCompanyId()); List<Role> roleList = user.getRoleList(); for (Role role : roleList) { authorizationInfo.addRole(role.getRoleName()); if (CommonUtil.check(role.getPowerList())) { 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 key = (String) authenticationToken.getPrincipal(); SysUser u = new SysUser(); u.setAccNum(key); SysUser user = userService.getUserByAcc(u); if (user == null) { throw new UnknownAccountException(); } else if ("0".equals(user.getIsLock())) { throw new LockedAccountException(); // 帐号冻结,非正常 // } // SysUser admin = userService.getByUId(user.getCreaterId()); // if(admin != null && !"00".equals(admin.getUserState())){ // throw new LockedAccountException(); // 管理员帐号被冻结,非正常 } else { SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user, user.getPasswd(), this.getName()); return simpleAuthenticationInfo; } } } }