shiro的session都是存在缓存中的,所有会有一个sessionDAO的类来做CRUD操作,这个类就是org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO。
它继承了CachingSessionDAO这个类,而这个类又是AbstractSessionDAO的子类和CacheManagerAware的实现类,源码如下:public class EnterpriseCacheSessionDAO extends CachingSessionDAO { public EnterpriseCacheSessionDAO() { setCacheManager(new AbstractCacheManager() { @Override protected CachecreateCache(String name) throws CacheException { return new MapCache (name, new ConcurrentHashMap ()); } }); } protected Serializable doCreate(Session session) { Serializable sessionId = generateSessionId(session); assignSessionId(session, sessionId); return sessionId; } protected Session doReadSession(Serializable sessionId) { return null; //should never execute because this implementation relies on parent class to access cache, which //is where all sessions reside - it is the cache implementation that determines if the //cache is memory only or disk-persistent, etc. } protected void doUpdate(Session session) { //does nothing - parent class persists to cache. } protected void doDelete(Session session) { //does nothing - parent class removes from cache. }}
从源码可以看出doReadSession、doUpdate和doDelete方法没有实体代码。我们自己的类继承EnterpriseCacheSessionDAO并重写相应的方法即可:
package org.liuyuantao.kms.shiro;import org.apache.shiro.session.Session;import org.apache.shiro.session.mgt.ValidatingSession;import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.transaction.annotation.Transactional;import java.io.Serializable;import java.util.List;@Transactionalpublic class CustomSessionDAO extends EnterpriseCacheSessionDAO { @Autowired private JdbcTemplate jdbcTemplate; @Override protected Serializable doCreate(Session session) { Serializable sessionId = generateSessionId(session); assignSessionId(session, sessionId); String sql = "insert into app_session(id, session) values(?,?)"; jdbcTemplate.update(sql, sessionId, SerializableUtils.serialize(session)); return session.getId(); } @Override protected Session doReadSession(Serializable sessionId) { String sql = "select session from app_session where id=?"; ListsessionStrList = jdbcTemplate.queryForList(sql, String.class, sessionId); if (sessionStrList.size() == 0) return null; return SerializableUtils.deserialize(sessionStrList.get(0)); } @Override protected void doUpdate(Session session) { if (session instanceof ValidatingSession && !((ValidatingSession) session).isValid()) { return; } String sql = "update app_session set session=? where id=?"; jdbcTemplate.update(sql, SerializableUtils.serialize(session), session.getId()); } @Override protected void doDelete(Session session) { String sql = "delete from app_session where id=?"; jdbcTemplate.update(sql, session.getId()); }}
Spring的配置文件添加bean的配置:
这里要特别注意下sessionManager的class,web应用的话最好使用DefaultWebSessionManager,如果使用DefaultWebSessionManager的父类DefaultSessionManager,可能会出现一些想不到的后果,比如使用kaptcha来实现验证码的时候一直是验证码不正确,因为session的上下文不是在web环境...