介绍
通过 SessionDao
可以把 Session
保存在我们想要保存的地方,比如 MySQL,也可以是 Redis,甚至是一个文件,我们可以自定义它的 CRUD 操作。下面是 Shiro 提供的几个 SessionDao
管理实现:
org.apache.shiro.session.mgt.eis.AbstractSessionDAO
:提供了org.apache.shiro.session.mgt.eis.SessionDAO
的基本实现,如生成会话 ID 等。org.apache.shiro.session.mgt.eis.CachingSessionDAO
:提供了对开发者透明的会话缓存功能,需要设置相应的CacheManager
。org.apache.shiro.session.mgt.eis.MemorySessionDAO
:直接在内存中进行会话维护。org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO
:提供了缓存功能的会话维护,默认情况下使用MapCache
实现,内部使用ConcurrentHashMap
保存缓存的会话。
使用示例
下面是一个将 Session
保存在 MySQL 中的一个示例。
1、引入对象序列化工具类:
// com.zze.shiro.web.utils.SerializableUtils
import org.apache.shiro.codec.Base64;
import org.apache.shiro.session.Session;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SerializableUtils {
public static String serialize(Session session) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(session);
return Base64.encodeToString(bos.toByteArray());
} catch (Exception ex) {
throw new RuntimeException("serialize session error", ex);
}
}
public static Session deSerialize(String sessionStr) {
try {
ByteArrayInputStream bis = new ByteArrayInputStream(Base64.decode(sessionStr));
ObjectInputStream ois = new ObjectInputStream(bis);
return (Session) ois.readObject();
} catch (Exception ex) {
throw new RuntimeException("deserialize session error", ex);
}
}
}
2、自定义 SessionDao
的实现,重写对 Session CRUD 的方法:
// com.zze.shiro.web.utils.MySessionDao
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.ValidatingSession;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.springframework.jdbc.core.JdbcTemplate;
import java.io.Serializable;
import java.util.List;
public class MySessionDao extends EnterpriseCacheSessionDAO {
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
protected Serializable doCreate(Session session) {
Serializable sessionId = super.doCreate(session);
String sql = "insert into sessions(id,session) values(?,?)";
jdbcTemplate.update(sql, sessionId, SerializableUtils.serialize(session));
return session.getId();
}
@Override
protected Session doReadSession(Serializable sessionId) {
String sql ="select session from sessions where id=?";
List<String> sessionStrList = 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 sessions set session=? where id=?";
jdbcTemplate.update(sql, SerializableUtils.serialize(session), session.getId());
}
@Override
protected void doDelete(Session session) {
String sql = "delete from sessions where id=?";
jdbcTemplate.update(sql, session.getId());
}
}
3、配置 SessionDao
:
<!--配置数据源-->
<bean name="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///test"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<!--JDBC 模板-->
<bean name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--SessionId 生成器-->
<bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"/>
<!--sessionDao-->
<bean id="sessionDao" class="com.zze.shiro.web.utils.MySessionDao">
<!--缓存名称,对应 ehcache.xml 中的缓存名称-->
<property name="activeSessionsCacheName" value="shiro-activeSessionCache"/>
<!--指定 SessionId 生成器-->
<property name="sessionIdGenerator" ref="sessionIdGenerator"/>
<!--注入 jdbc 模板-->
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<!--会话管理器-->
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<property name="sessionDAO" ref="sessionDao"/>
<!-- Session 失效时长,单位毫秒 -->
<property name="globalSessionTimeout" value="1800000"/>
<!-- 删除失效的 Session -->
<property name="deleteInvalidSessions" value="true"/>
<!-- 是否定期检查 Session 的有效性 -->
<property name="sessionValidationSchedulerEnabled" value="true"/>
<property name="sessionListeners">
<list>
<ref bean="shiroSessionListener"/>
</list>
</property>
</bean>
Shiro 提供了会话验证调度器,用于定期的验证会话是否已过期,如果过期将会停止会话。出于性能考虑,一般情况下都是获取会话时来验证会话是否过期并停止会话的,但如果在 web 环境中,如果用户不主动退出是不知道会话是否过期的,因此需要定期的检测会话是否过期,Shiro 提供了会话验证调度器 org.apache.shiro.session.mgt.SessionValidationScheduler
,也提供了使用 Quartz 的会话验证调度器:org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler
。
评论区