Shiro 在线回话管理

项目做的多了,遇到的奇葩需求也就多。有时候需要显示当前在线人数、当前在线用户,有时候可能需要强制某个用户下线等;此时就需要获取相应的在线用户并进行一些操作。本文结合Shiro为大家分享关于在线回话管理的项目。

会话控制器

@RequiresPermissions("session:*")  
@Controller  
@RequestMapping("/sessions")  
public class SessionController {  
    @Autowired  
    private SessionDAO sessionDAO;  
    @RequestMapping()  
    public String list(Model model) {  
        Collection<Session> sessions =  sessionDAO.getActiveSessions();  
        model.addAttribute("sessions", sessions);  
        model.addAttribute("sesessionCount", sessions.size());  
        return "sessions/list";  
    }  
    @RequestMapping("/{sessionId}/forceLogout")  
    public String forceLogout(@PathVariable("sessionId") String sessionId,   
        RedirectAttributes redirectAttributes) {  
        try {  
            Session session = sessionDAO.readSession(sessionId);  
            if(session != null) {  
                session.setAttribute(  
                    Constants.SESSION_FORCE_LOGOUT_KEY, Boolean.TRUE);  
            }  
        } catch (Exception e) {/*ignore*/}  
        redirectAttributes.addFlashAttribute("msg", "强制退出成功!");  
        return "redirect:/sessions";  
    }  
}   
  • list方法:提供了展示所有在线会话列表,通过sessionDAO.getActiveSessions()获取所有在线的会话。
  • forceLogout方法:强制退出某一个会话,此处只在指定会话中设置Constants.SESSION_FORCE_LOGOUT_KEY属性,之后通过ForceLogoutFilter判断并进行强制退出。

此处展示会话列表的缺点是:sessionDAO.getActiveSessions()提供了获取所有活跃会话集合,如果做一般企业级应用问题不大,因为在线用户不多;但是如果应用的在线用户非常多,此种方法就不适合了,解决方案就是分页获取:

Page<Session> getActiveSessions(int pageNumber, int pageSize); 

Page对象除了包含pageNumber、pageSize属性之外,还包含totalSessions(总会话数)、Collection<Session> (当前页的会话)。
 
分页获取时,如果是MySQL这种关系数据库存储会话比较好办,如果使用Redis这种数据库可以考虑这样存储:

session.id=会话序列化数据  
session.ids=会话id Set列表(接着可以使用LLEN获取长度,LRANGE分页获取)
//会话创建时(如sessionId=123),redis命令
SET session.123 "Session序列化数据"  
LPUSH session.ids 123 
//会话删除时(如sessionId=123),redis命令
DEL session.123  
LREM session.ids 123
//获取总活跃会话
LLEN session.ids
//分页获取活跃会话
LRANGE key 0 10 #获取到会话ID  
MGET session.1 session.2……  #根据第一条命令获取的会话ID获取会话数据 

ForceLogoutFilter 强制退出过滤器

public class ForceLogoutFilter extends AccessControlFilter {  
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {  
        Session session = getSubject(request, response).getSession(false);  
        if(session == null) {  
            return true;  
        }  
        return session.getAttribute(Constants.SESSION_FORCE_LOGOUT_KEY) == null;  
    }  
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {  
        try {  
            getSubject(request, response).logout();//强制退出  
        } catch (Exception e) {/*ignore exception*/}  
        String loginUrl = getLoginUrl() + (getLoginUrl().contains("?") ? "&" : "?") + "forceLogout=1";  
        WebUtils.issueRedirect(request, response, loginUrl);  
        return false;  
    }  
}   

强制退出拦截器,如果用户会话中存在Constants.SESSION_FORCE_LOGOUT_KEY属性,表示被管理员强制退出了;然后调用Subject.logout()退出,且重定向到登录页面(自动拼上fourceLogout请求参数)。

登录控制器

在LoginController类的showLoginForm方法中最后添加如下代码:

if(req.getParameter("forceLogout") != null) {  
    model.addAttribute("error", "您已经被管理员强制退出,请重新登录");  
}  

即如果有请求参数forceLogout表示是管理员强制退出的,在界面上显示相应的信息。

Shiro配置spring-config-shiro.xml

在shiroFilter中的filterChainDefinitions拦截器链定义中添加了forceLogout拦截器:

/** = forceLogout,user,sysUser

项目运行效果

首先输入http://localhost:8080/shiro19/跳转到登录页面输入admin/123456登录;

登录成功后,点击菜单的“会话管理”,可以看到当前在线会话列表:

Shiro 在线回话管理

点击“强制退出”按钮,会话相应的用户再点击界面的话会看到如下界面,表示已经被强制退出了:

Shiro 强制退出功能

本文案例源代码下载链接:http://pan.baidu.com/s/1hsl4lr2 密码:o83e

Shiro 在线回话管理

: » Shiro 在线回话管理

原创文章,作者:306829225,如若转载,请注明出处:https://blog.ytso.com/tech/java/251564.html

(0)
上一篇 2022年5月3日 05:32
下一篇 2022年5月3日 05:39

相关推荐

发表回复

登录后才能评论