Cookie/Session 是常见的状态管理,Shiro提供了完整的企业级会话管理功能。 本文在上一篇文章 Shiro功能应用(三)–EHCache缓存代码基础进行添加Session管理。
代码实现:
代码地址:
https://github.com/OooooOz/SpringBoot-Shiro
ShiroConfig的安全管理器SecurityManager:
@Bean(name="securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("shiroRealm") MyShiroRealm shiroRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(shiroRealm);
securityManager.setRememberMeManager(rememberMeManager()); //实现记住我
securityManager.setCacheManager(getEhCacheManager()); //实现缓存
securityManager.setSessionManager(sessionManager()); //session管理
return securityManager;
}
ShiroConfig的会话管理器sessionManager:
@Bean("sessionManager")
public SessionManager sessionManager() {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
Collection<SessionListener> listeners = new ArrayList<SessionListener>();
listeners.add(sessionListener()); //配置监听
sessionManager.setSessionListeners(listeners);
sessionManager.setSessionIdCookie(sessionIdCookie());
sessionManager.setSessionDAO(sessionDAO());
sessionManager.setCacheManager(getEhCacheManager());
sessionManager.setGlobalSessionTimeout(10000); //全局会话超时时间(单位毫秒),默认30分钟 暂时设置为10秒钟 用来测试
sessionManager.setDeleteInvalidSessions(true); //是否开启删除无效的session对象 默认为true
// sessionManager.setSessionValidationSchedulerEnabled(true); //是否开启定时调度器进行检测过期session 默认为true
//设置session失效的扫描时间, 清理用户直接关闭浏览器造成的孤立会话 默认为 1个小时
// sessionManager.setSessionValidationInterval(5000); //暂时设置为 5秒 用来测试
sessionManager.setSessionIdUrlRewritingEnabled(false); //取消url 后面的 JSESSIONID
return sessionManager;
}
ShiroConfig的session监听:
@Bean("sessionListener")
public ShiroSessionListener sessionListener(){
ShiroSessionListener sessionListener = new ShiroSessionListener();
return sessionListener;
}
ShiroConfig的SessionDAO:
@Bean
public SessionDAO sessionDAO() {
EnterpriseCacheSessionDAO enterpriseCacheSessionDAO = new EnterpriseCacheSessionDAO();
//使用ehCacheManager
enterpriseCacheSessionDAO.setCacheManager(getEhCacheManager());
//设置session缓存的名字 默认为 shiro-activeSessionCache
enterpriseCacheSessionDAO.setActiveSessionsCacheName("shiro-activeSessionCache");
//sessionId生成器
enterpriseCacheSessionDAO.setSessionIdGenerator(sessionIdGenerator());
return enterpriseCacheSessionDAO;
}
ShiroConfig的会话ID生成器:
@Bean
public SessionIdGenerator sessionIdGenerator() {
return new JavaUuidSessionIdGenerator();
}
ShiroConfig的会话管理的Cookie:
/**
* 查询定义sessionId的cookie,防止与SERVLET容器的冲突,默认JSESSIONID
* 注意:这里的cookie 不是上面的记住我 cookie 记住我需要一个cookie|session管理也需要自己的cookie
*/
@Bean("sessionIdCookie")
public SimpleCookie sessionIdCookie(){
SimpleCookie simpleCookie = new SimpleCookie("sid"); //cookie的名称
simpleCookie.setHttpOnly(true); //设为true后,只能通过http访问,javascript无法访问
simpleCookie.setPath("/");
simpleCookie.setMaxAge(-1); //maxAge=-1表示浏览器关闭时失效此Cookie
return simpleCookie;
}
Session监听类:
package com.demo.config;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.SessionListener;
import java.util.concurrent.atomic.AtomicInteger;
public class ShiroSessionListener implements SessionListener{
/**
* 统计在线人数,juc包下线程安全自增
*/
private final AtomicInteger sessionCount = new AtomicInteger(0);
/**
* 会话创建时触发
*/
@Override
public void onStart(Session session) {
//会话创建,在线人数加一
sessionCount.incrementAndGet();
}
/**
* 退出会话时触发
*/
@Override
public void onStop(Session session) {
//会话退出,在线人数减一
sessionCount.decrementAndGet();
}
/**
* 会话过期时触发
*/
@Override
public void onExpiration(Session session) {
//会话过期,在线人数减一
sessionCount.decrementAndGet();
}
/**
* 获取在线人数使用
* @return
*/
public AtomicInteger getSessionCount() {
return sessionCount;
}
}
控制器:
@RequestMapping("/userList.do")
public String userList(Model model){
//查询所有的用户信息并且显示到页面上
Subject subject = SecurityUtils.getSubject();
System.out.println("------是否通过认证:"+subject.isAuthenticated()+"------是否记住我:"+subject.isRemembered());
List<User> list = userService.findAll();
model.addAttribute("userList", list);
model.addAttribute("count",shiroSessionListener.getSessionCount());
return "userList";
}
页面获取在线人数
当前在线人数:'[[${count}]]'
功能测试:
访问http://localhost:8080/userList.do登陆后,不关闭浏览器再次访问改地址,是一样可以访问的,Web容器的Session一般默认30min才失效。
本例中设置sessionManager.setGlobalSessionTimeout(10000); 也就是Shiro管理的session10秒后失效,所以登陆后页面不作任何操作,10s后再访问,session失效则需重新登陆。
会话监听器实现SessionListener接口,页面能够获取统计的在线人数,