Session Storage
为了方便应用程序能随时访问Session,Session在创建或更新之后,需要将其持久化。与持久化类似,当Session无效且使用时间较长时,需要删除Session,以防止Session的存储空间耗尽。
SessionDAO
Session的增、删、改、查等操作都由SessionManager的实现类委托给其内部组件SessionDAO完成。
当你使用的是native session
时,session的默认存储在内存中。其实你还可以将Session存储在文件系统中、关系数据库或非关系型数据中等地方。
因为session
的所有操作都是由SessionDAO
完成的,所以,如果你想自定义session
的存储位置,那么你需要编写SessionDAO
的实现类。
其实,Shiro本身已经提供了SessionDAO
的实现类,比如:AbstractSessionDAO
,CachingSessionDAO
,EnterpriseCacheSessionDAO
,MemorySessionDAO
等,所以你只需要根据你的实际需要继承它们即可。
SessionDAO应用
自定义session
的存储位置有什么用呢?其实,当你的应用程序部署多个节点,即使用了负载均衡,为了在多个节点之间共享session
,你需要将session
信息存储至缓存中。这时,你就需要自定义session
的存储位置了。
下面显示了如何在多个节点之间共享session,示例代码中使用Redis作为session的存储媒介,示例代码如下。
java 代码
public class RedisSessionDAO extends AbstractSessionDAO {
private static Logger logger = LoggerFactory.getLogger(RedisSessionDAO.class);
/**
* The Redis key prefix for the sessions
*/
private String keyPrefix = "shiro_session:";
/**
* shiro-redis的session对象前缀
*/
private RedisManager redisManager;
@Override
public void update(Session session) throws UnknownSessionException {
this.saveSession(session);
}
/**
* save session
*
* @param session
* @throws UnknownSessionException
*/
private void saveSession(Session session) throws UnknownSessionException {
if(session == null || session.getId() == null) {
logger.error("session or session id is null");
return;
}
byte[] key = getByteKey(session.getId());
byte[] value = SerializeUtils.serialize(session);
session.setTimeout(redisManager.getExpire());
this.redisManager.set(key, value, redisManager.getExpire());
}
@Override
public void delete(Session session) {
if(session == null || session.getId() == null) {
logger.error("session or session id is null");
return;
}
redisManager.del(this.getByteKey(session.getId()));
}
@Override
public Collection<Session> getActiveSessions() {
Set<Session> sessions = new HashSet<Session>();
Set<byte[]> keys = redisManager.keys(this.keyPrefix + "*");
if(keys != null && keys.size() > 0) {
for(byte[] key : keys) {
Session s = (Session) SerializeUtils.deserialize(redisManager.get(key));
sessions.add(s);
}
}
return sessions;
}
@Override
protected Serializable doCreate(Session session) {
Serializable sessionId = this.generateSessionId(session);
this.assignSessionId(session, sessionId);
this.saveSession(session);
return sessionId;
}
@Override
protected Session doReadSession(Serializable sessionId) {
if(sessionId == null) {
logger.error("session id is null");
return null;
}
Session s = (Session) SerializeUtils.deserialize(redisManager.get(this.getByteKey(sessionId)));
return s;
}
/**
* 获得byte[]型的key
*
* @param sessionId
*/
private byte[] getByteKey(Serializable sessionId) {
String preKey = this.keyPrefix + sessionId;
return preKey.getBytes();
}
public RedisManager getRedisManager() {
return redisManager;
}
public void setRedisManager(RedisManager redisManager) {
this.redisManager = redisManager;
this.redisManager.init();
}
/**
* Returns the Redis session keys prefix.
*
* @return The prefix
*/
public String getKeyPrefix() {
return keyPrefix;
}
/**
* Sets the Redis sessions key prefix.
*
* @param keyPrefix The prefix
*/
public void setKeyPrefix(String keyPrefix) {
this.keyPrefix = keyPrefix;
}
}
ini 配置代码
sessionDAO = com.xxx.xxx.RedisSessionDAO
securityManager.sessionManager.sessionDAO = $sessionDAO