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实现类如下
Shiro - 会话管理


HttpSession实现类如下:

Shiro - 会话管理


【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;
	}