前言:
目前咱们对“apache shiro”可能比较关怀,同学们都想要知道一些“apache shiro”的相关文章。那么小编在网摘上网罗了一些关于“apache shiro””的相关知识,希望同学们能喜欢,姐妹们一起来了解一下吧!第七章 实现分布式会话SessionManager1、会话的问题2、分布式会话实现思路【1】原理分析
所有服务器的session信息都存储到了同一个Redis集群中,即所有的服务都将 Session 的信息存储到 Redis 集群中,无论是对 Session 的注销、更新都会同步到集群中,达到了 Session 共享的目的。
Cookie 保存在客户端浏览器中,而 Session 保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上,这就是 Session。客户端浏览器再次访问时只需要从该 Session 中查找该客户的状态就可以了。
在实际工作中我们建议使用外部的缓存设备(包括Redis)来共享 Session,避免单个服务器节点挂掉而影响服务,共享数据都会放到外部缓存容器中
【2】设计类图详解3、RedisSessionDao
RedisSessionDao继承AbstractSessionDAO,重写了会话的创建、读取、修改等操作,全部缓存与redis中
package com.itheima.shiro.core.impl;import com.itheima.shiro.constant.CacheConstant;import com.itheima.shiro.utils.ShiroRedissionSerialize;import lombok.extern.log4j.Log4j2;import org.apache.shiro.session.Session;import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;import org.redisson.api.RBucket;import org.redisson.api.RedissonClient;import javax.annotation.Resource;import java.io.Serializable;import java.util.Collection;import java.util.Collections;import java.util.concurrent.TimeUnit;/** * @Description 实现shiro session的memcached集中式管理~ */@Log4j2public class RedisSessionDao extends AbstractSessionDAO { @Resource(name = "redissonClientForShiro") RedissonClient redissonClient; private Long globalSessionTimeout; @Override protected Serializable doCreate(Session session) { Serializable sessionId = generateSessionId(session); assignSessionId(session, sessionId);// log.info("=============创建sessionId:{}",sessionId); RBucket<String> sessionIdRBucket = redissonClient.getBucket(CacheConstant.GROUP_CAS+sessionId.toString()); sessionIdRBucket.trySet(ShiroRedissionSerialize.serialize(session), globalSessionTimeout, TimeUnit.SECONDS); return sessionId; } @Override protected Session doReadSession(Serializable sessionId) { RBucket<String> sessionIdRBucket = redissonClient.getBucket(CacheConstant.GROUP_CAS+sessionId.toString()); Session session = (Session) ShiroRedissionSerialize.deserialize(sessionIdRBucket.get());// log.info("=============读取sessionId:{}",session.getId().toString()); return session; } @Override public void delete(Session session) {// log.info("=============删除sessionId:{}",session.getId().toString()); RBucket<String> sessionIdRBucket = redissonClient.getBucket(CacheConstant.GROUP_CAS+session.getId().toString()); sessionIdRBucket.delete(); } @Override public Collection<Session> getActiveSessions() { return Collections.emptySet(); } @Override public void update(Session session) { RBucket<String> sessionIdRBucket = redissonClient.getBucket(CacheConstant.GROUP_CAS+session.getId().toString()); sessionIdRBucket.set(ShiroRedissionSerialize.serialize(session), globalSessionTimeout, TimeUnit.SECONDS);// log.info("=============修改sessionId:{}",session.getId().toString()); } public void setGlobalSessionTimeout(Long globalSessionTimeout) { this.globalSessionTimeout = globalSessionTimeout; }}4、重写ShiroConfig
package com.itheima.shiro.config;import com.itheima.shiro.core.ShiroDbRealm;import com.itheima.shiro.core.impl.RedisSessionDao;import com.itheima.shiro.core.impl.ShiroCacheManager;import com.itheima.shiro.core.impl.ShiroDbRealmImpl;import com.itheima.shiro.filter.RolesOrAuthorizationFilter;import com.itheima.shiro.properties.PropertiesUtil;import lombok.extern.log4j.Log4j2;import org.apache.shiro.session.mgt.eis.SessionDAO;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.DefaultWebSecurityManager;import org.apache.shiro.web.servlet.SimpleCookie;import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;import org.redisson.Redisson;import org.redisson.api.RedissonClient;import org.redisson.config.Config;import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.context.properties.EnableConfigurationProperties;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.DependsOn;import javax.servlet.Filter;import java.util.HashMap;import java.util.LinkedHashMap;import java.util.List;import java.util.Map;/** * @Description 权限配置类 */@Configuration@ComponentScan(basePackages = "com.itheima.shiro.core")@EnableConfigurationProperties({ShiroRedisProperties.class})@Log4j2public class ShiroConfig { @Autowired private ShiroRedisProperties shiroRedisProperties; /** * @Description redission客户端 */ @Bean("redissonClientForShiro") public RedissonClient redissonClient() { log.info("=====初始化redissonClientForShiro开始======"); String[] nodeList = shiroRedisProperties.getNodes().split(","); Config config = new Config(); if (nodeList.length == 1) { config.useSingleServer().setAddress(nodeList[0]) .setConnectTimeout(shiroRedisProperties.getConnectTimeout()) .setConnectionMinimumIdleSize(shiroRedisProperties.getConnectionMinimumidleSize()) .setConnectionPoolSize(shiroRedisProperties.getConnectPoolSize()).setTimeout(shiroRedisProperties.getTimeout()); } else { config.useClusterServers().addNodeAddress(nodeList) .setConnectTimeout(shiroRedisProperties.getConnectTimeout()) .setMasterConnectionMinimumIdleSize(shiroRedisProperties.getConnectionMinimumidleSize()) .setMasterConnectionPoolSize(shiroRedisProperties.getConnectPoolSize()).setTimeout(shiroRedisProperties.getTimeout()); } RedissonClient redissonClient = Redisson.create(config); log.info("=====初始化redissonClientForShiro完成======"); return redissonClient; } /** * @Description 创建cookie对象 */ @Bean(name="sessionIdCookie") public SimpleCookie simpleCookie(){ SimpleCookie simpleCookie = new SimpleCookie(); simpleCookie.setName("ShiroSession"); return simpleCookie; } /** * @Description 权限管理器 * @param * @return */ @Bean(name="securityManager") public DefaultWebSecurityManager defaultWebSecurityManager(){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(shiroDbRealm()); securityManager.setSessionManager(shiroSessionManager()); return securityManager; } /** * @Description 自定义RealmImpl */ @Bean(name="shiroDbRealm") public ShiroDbRealm shiroDbRealm(){ return new ShiroDbRealmImpl(); } /** * @Description 自定义session会话存储的实现类 ,使用Redis来存储共享session,达到分布式部署目的 */ @Bean("redisSessionDao") public SessionDAO redisSessionDao(){ RedisSessionDao sessionDAO = new RedisSessionDao(); sessionDAO.setGlobalSessionTimeout(shiroRedisProperties.getGlobalSessionTimeout()); return sessionDAO; } /** * @Description 会话管理器 */ @Bean(name="sessionManager") public DefaultWebSessionManager shiroSessionManager(){ DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); sessionManager.setSessionDAO(redisSessionDao()); sessionManager.setSessionValidationSchedulerEnabled(false); sessionManager.setSessionIdCookieEnabled(true); sessionManager.setSessionIdCookie(simpleCookie()); sessionManager.setGlobalSessionTimeout(shiroRedisProperties.getGlobalSessionTimeout()); return sessionManager; } /** * @Description 保证实现了Shiro内部lifecycle函数的bean执行 */ @Bean(name = "lifecycleBeanPostProcessor") public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } /** * @Description AOP式方法级权限检查 */ @Bean @DependsOn("lifecycleBeanPostProcessor") public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); defaultAdvisorAutoProxyCreator.setProxyTargetClass(true); return defaultAdvisorAutoProxyCreator; } /** * @Description 配合DefaultAdvisorAutoProxyCreator事项注解权限校验 */ @Bean public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor() { AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor(); aasa.setSecurityManager(defaultWebSecurityManager()); return new AuthorizationAttributeSourceAdvisor(); } /** * @Description 过滤器链 */ private Map<String, String> filterChainDefinition(){ List<Object> list = PropertiesUtil.propertiesShiro.getKeyList(); Map<String, String> map = new LinkedHashMap<>(); for (Object object : list) { String key = object.toString(); String value = PropertiesUtil.getShiroValue(key); log.info("读取防止盗链控制:---key{},---value:{}",key,value); map.put(key, value); } return map; } /** * @Description 自定义过滤器定义 */ private Map<String, Filter> filters() { Map<String, Filter> map = new HashMap<String, Filter>(); map.put("roleOr", new RolesOrAuthorizationFilter()); return map; } /** * @Description Shiro过滤器 */ @Bean("shiroFilter") public ShiroFilterFactoryBean shiroFilterFactoryBean(){ ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean(); shiroFilter.setSecurityManager(defaultWebSecurityManager()); //使自定义过滤器生效 shiroFilter.setFilters(filters()); shiroFilter.setFilterChainDefinitionMap(filterChainDefinition()); shiroFilter.setLoginUrl("/login"); shiroFilter.setUnauthorizedUrl("/login"); return shiroFilter; }}5、测试
此时我们需要2个相同的项目shiro-day01-12shiro-redis-SessionManager-A和shiro-day01-13shiro-redis-SessionManager-B
分别启动A,B2个项目
访问,使用admin/pass登录
修改地址栏为,也可以正常访问
此时我们实现了在A服务登录,直接访问B服务则无需登录
标签: #apache shiro