龙空技术网

java:shiro高级篇——3

黑马程序员 365

前言:

目前咱们对“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