Shiro - 会话管理
Shiro提供了完整的企业级会话管理功能,不依赖于底层容器(如web容器tomcat),不管JavaSE还是JavaEE环境都可以使用,提供了会话管理、会话事件监听、会话存储/持久化、容器无关的集群、失效/过期支持、对Web 的透明支持、SSO 单点登录的支持等特性。
【1】Shiro Session接口与实现类
这里的Session不再是我们通常使用的javax.servlet.http.HttpSession,而是org.apache.shiro.session.Session。
一个Session是与一段时间内与软件系统交互的单个对象(用户、守护进程等)相关的有状态数据上下文。
该Session旨在由业务层管理,并且可以通过其他层访问,而不绑定到任何给定的客户端技术。这是一个很大的好处对Java系统而言,因为到目前为止,唯一可行的会话机制是{javax .servlet .http.httpsession }或有状态会话EJB,这些应用程序多次不必要地将应用程序耦合到Web或EJB技术。
不过在使用上与httpsession 有相似之处,相关API如下:
- Subject.getSession():即可获取会话;其等价于Subject.getSession(true),即如果当前没有创建Session 对象会创建一个;Subject.getSession(false),如果当前没有创建Session 则返回null
- session.getId():获取当前会话的唯一标识
- session.getHost():获取当前Subject的主机地址
- session.getTimeout() & session.setTimeout(毫秒):获取/设置当前Session的过期时间
- session.getStartTimestamp() & session.getLastAccessTime():获取会话的启动时间及最后访问时间。
如果是JavaSE应用需要自己定期调用session.touch() 去更新最后访问时间;如果是Web 应用,每次进入ShiroFilter都会自动调用session.touch() 来更新最后访问时间。 - session.touch() & session.stop():更新会话最后访问时间及销毁会话。
当Subject.logout()时会自动调用stop 方法来销毁会话。如果在web中,调用HttpSession. invalidate() 也会自动调用ShiroSession.stop方法进行销毁Shiro的会话 - session.setAttribute(key, val) & session.getAttribute(key) & session.removeAttribute(key):设置/获取/删除会话属性;在整个会话范围内都可以对这些属性进行操作。
Session实现类如下
HttpSession实现类如下:
【2】会话监听器
会话监听器用于监听会话创建、过期及停止事件。
源码如下:
public interface SessionListener {
/**
* Notification callback that occurs when the corresponding Session has started.
*
* @param session the session that has started.
*/
void onStart(Session session);
/**
* Notification callback that occurs when the corresponding Session has stopped, either programmatically via
* {@link Session#stop} or automatically upon a subject logging out.
*
* @param session the session that has stopped.
*/
void onStop(Session session);
/**
* Notification callback that occurs when the corresponding Session has expired.
* <p/>
* <b>Note</b>: this method is almost never called at the exact instant that the {@code Session} expires. Almost all
* session management systems, including Shiro's implementations, lazily validate sessions - either when they
* are accessed or during a regular validation interval. It would be too resource intensive to monitor every
* single session instance to know the exact instant it expires.
* <p/>
* If you need to perform time-based logic when a session expires, it is best to write it based on the
* session's {@link org.apache.shiro.session.Session#getLastAccessTime() lastAccessTime} and <em>not</em> the time
* when this method is called.
*
* @param session the session that has expired.
*/
void onExpiration(Session session);
}
Shiro Session一个重要应用
在Controller通常会使用HttpSession进行操作,那么在Service层为了降低侵入、解耦,我们就可以使用Shiro Session进行操作。
如在Controller放入Session中一个键值对:
@ResponseBody
@RequestMapping(value="/test",produces="application/json;charset=utf-8")
public String test(HttpSession session) {
System.out.println("调用方法test");
session.setAttribute("key", "123456");
return "success";
}
在Service使用Shiro Session进行获取:
@Override
public List<SysRole> getRoleListByUserId(Long id) {
// TODO Auto-generated method stub
Session session = SecurityUtils.getSubject().getSession();
Object attribute = session.getAttribute("key");
List<SysRole> roleListByUserId = userServiceDao.getRoleListByUserId(id);
return roleListByUserId;
}