shiro的session管理

shiro的SessionManager

在官方架构图里面:
在这里插入图片描述
在默认的SecurityManager的uml图里面:
在这里插入图片描述
前面的CacheSecurityManager,realmSecurityManager,认证管理器,鉴权管理器都讲过了,那么这个Session管理器是怎么回事呢?

在web容器里面的session跟HttpSession是同一个吗?

首先看,我们在没有设置Session管理器的时候,默认使用的是哪一个?
先看SessionManager的具体实现:
在这里插入图片描述
第一个类是AbstractNativeSessionManager,是个抽象类,主要实现就是DefaultSessionManager跟DefaultWebSessionManager,而DefaultWebSessionManager又是继承了DefaultSessionManager,我们看一下DefaultWebSessionManager的uml图:
在这里插入图片描述
WebSessionManager里面就一个方法isServletContainerSessions判断是否是本地会话,就是相当于判断是不是httpSession.
再看SessionsSecurityManager,直接看我们使用的webSecurityManager:
在这里插入图片描述
ServletContainerSessionManager就相当于是使用HttpSession:ServletContainerSessionManager的createSession方法返回的是HttpServletSession,而HttpServletSession内部是直接维护了HttpSession对象,然后一系列方法是直接使用HttpSession进行操作的:
在这里插入图片描述
在这里插入图片描述

自定义sessionManager

看看ServletContainerSessionManager和DefaultWebSessionManager一起的uml图:
在这里插入图片描述
默认的是使用的ServletContainerSessionManager,如果我们想自定义,就直接使用DefaultWebSessionManager即可了;DefaultWebSessionManager需要设置的属性主要有:

  • SessionListener,session监听
  • setSessionDAO设置sessionDao,session缓存,或者持久化
  • sessionIdCookie设置cookie
  • setGlobalSessionTimeout全局会话超时时间
  • setDeleteInvalidSessions是否删除无效session,默认true
  • setSessionValidationSchedulerEnabled定时删除,默认true
  • setSessionValidationInterval设置多长时间检测一下是否有过期session.然后删除
  • setSessionIdUrlRewritingEnabled是否开启url后面加上sessionId

我们先看SessionDAO

sessionDao就是一系列的操作session的接口:
在这里插入图片描述
看实现:
在这里插入图片描述
抽象的就不看了,就三个具体实现:EnterpriseCacheSessionDAO,MemorySessionDAO,RedisSessionDAO,RedisSessionDAO就不说了比较简单,前面说shiro使用redis缓存的时候也说过了,这个那就是session缓存在redis里面,MemorySessionDAO也是,内部维护了一个ConcurrentMap来保存session,就是内存缓存了;EnterpriseCacheSessionDAO就是可以自己传一个CacheManager,好比ehcache的manager,然后就将缓存存在ehcache也可以直接传个内存缓存,也就放在内存里面了,也可以自定义sessionid的生成器,默认是JavaUuidSessionIdGenerator也就是uuid,可以自己实现.

使用内存缓存

直接使用MemorySessionDAO:

    @Bean
    public SessionDAO sessionDAO() {

        return new MemorySessionDAO();
        }

使用ehcache

        // ehcache
            public SessionDAO sessionDAO() {

        EnterpriseCacheSessionDAO enterpriseCacheSessionDAO = new EnterpriseCacheSessionDAO();
        EhCacheManager ehCacheManager = new EhCacheManager();
        ehCacheManager.setCacheManager(getEhCacheManager());
        enterpriseCacheSessionDAO.setCacheManager(ehCacheManager);
        enterpriseCacheSessionDAO.setActiveSessionsCacheName("shiro-activeSessionCache");
        enterpriseCacheSessionDAO.setSessionIdGenerator(new JavaUuidSessionIdGenerator());
        return enterpriseCacheSessionDAO;
        }

使用redis

org.crazycake.shiro.RedisSessionDAO的包注意:

  public SessionDAO sessionDAO() {
  
        //redis
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        RedisManager redisManager = new RedisManager();
        redisSessionDAO.setRedisManager(redisManager);
        return redisSessionDAO;

    }

剩下的配置比较简单:

    /**
     * 配置会话管理器,设定会话超时及保存
     * @return
     */
    @Bean
    public SessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        Collection<SessionListener> listeners = new ArrayList<SessionListener>();
        //配置监听
        listeners.add(new ShiroSessionListener());
        sessionManager.setSessionListeners(listeners);
        sessionManager.setSessionIdCookie(sessionIdCookie());
        sessionManager.setSessionDAO(sessionDAO());
        sessionManager.setCacheManager(new MemoryConstrainedCacheManager());

        sessionManager.setGlobalSessionTimeout(10000);
        sessionManager.setDeleteInvalidSessions(true);
        sessionManager.setSessionValidationSchedulerEnabled(true);
        sessionManager.setSessionValidationInterval(5000);
        sessionManager.setSessionIdUrlRewritingEnabled(false);

        return sessionManager;
    }

  @Bean("sessionIdCookie")
    public SimpleCookie sessionIdCookie(){
        SimpleCookie simpleCookie = new SimpleCookie("sid");
        simpleCookie.setHttpOnly(true);
        simpleCookie.setPath("/");
        //maxAge=-1表示浏览器关闭时失效此Cookie
        simpleCookie.setMaxAge(-1);
        return simpleCookie;
    }

需要自己实现session监听:

public interface SessionListener {
    void onStart(Session var1);

    void onStop(Session var1);

    void onExpiration(Session var1);
}

记录人数的:

public class ShiroSessionListener implements SessionListener {

    /**
     * 统计在线人数
     * juc包下线程安全自增
     */
    private final AtomicInteger sessionCount = new AtomicInteger(0);

    /**
     * 会话创建时触发
     * @param session
     */
    @Override
    public void onStart(Session session) {
        //会话创建,在线人数加一
        sessionCount.incrementAndGet();
    }

    /**
     * 退出会话时触发
     * @param session
     */
    @Override
    public void onStop(Session session) {
        //会话退出,在线人数减一
        sessionCount.decrementAndGet();
    }

    /**
     * 会话过期时触发
     * @param session
     */
    @Override
    public void onExpiration(Session session) {
        //会话过期,在线人数减一
        sessionCount.decrementAndGet();
    }
    /**
     * 获取在线人数使用
     * @return
     */
    public AtomicInteger getSessionCount() {
        return sessionCount;
    }
}

总结

这里是web的session简单用法,如果是java环境,那么session就比较简单了,前面都有分析到.不过现在一般都不使用session了,所以这一块,只需要知道就好了,现在项目一般都是有app端的,集群的,多应用共享的,就是单点登录这样的.所以基于传统的session已经很难实现需求了,解决方案一般是shiro+jwt基于token方式实现.后期会讲到

posted @ 2020-01-07 19:45  你就像甜甜的益达  阅读(544)  评论(0编辑  收藏  举报