刨析 Shiro 的 SecurityManager 实现单用户登录
通过这个可以看出 SecurityManager 中存储了那些 SessionId ,
public void getShiroManagerCache() {
System.out.println("查询保存到ShiroManagerCache的SessionId为~");
String currentUserSessionId = SecurityUtils.getSubject().getSession().getId().toString();
System.out.println(currentUserSessionId);
CrmSysUser user = (CrmSysUser) SecurityUtils.getSubject().getPrincipal();
DefaultWebSecurityManager securityManager = (DefaultWebSecurityManager) SecurityUtils.getSecurityManager();
DefaultWebSessionManager sessionManager = (DefaultWebSessionManager) securityManager.getSessionManager();
Collection<Session> sessions = sessionManager.getSessionDAO().getActiveSessions();
if (sessions.size() > 1) {
for (Session onlineSession : sessions) {
System.out.println("SessionId为[" + onlineSession.getId() + "]的Session信息!");
}
}
}

Shiro单用户登录,清理之前登录的用户 ,以下的方法会清除掉其他的 SessionId
/**
* new SimpleAuthenticationInfo(user, pwd, this.getName())中的第一个参数是SysUser对象,
* 在其他接收的地方也要转成SysUser对象,使用对象这里对应的处理方式是采用方法一,
* 如果是传递的userName字符串,则采用方法二进行处理
*/
SimpleAuthenticationInfo authcInfo = new SimpleAuthenticationInfo(user, pwd, this.getName());
方法一:传入的参数是User对象
/**
* @功能描述: 单用户登录,清除当前用户以前登录时保存的session会话
* @param loginName
*/
public void singleUseLogin(String loginName){
// 1.获取当前用户sessionId
String currentUserSessionId = SecurityUtils.getSubject().getSession().getId().toString();
// 2.获取shiro的sessionManager
DefaultWebSecurityManager securityManager = (DefaultWebSecurityManager) SecurityUtils.getSecurityManager();
DefaultWebSessionManager sessionManager = (DefaultWebSessionManager)securityManager.getSessionManager();
// 3.获取所有已登录用户的session列表
Collection<Session> sessions = sessionManager.getSessionDAO().getActiveSessions();
if (sessions.size() > 1) {
System.out.println("仅允许单用户登录,开始清理遗留用户信息~");
User user = null;
for(Session onlineSession:sessions){
// 4. 获取已登录用户的session的key值
SimplePrincipalCollection simplePrincipalCollection = (SimplePrincipalCollection) onlineSession.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
if (null == simplePrincipalCollection) {
sessionManager.getSessionDAO().delete(onlineSession);
continue;
}
// 5. 获取new SimpleAuthenticationInfo(user, pwd, this.getName())中放进去的第一个参数
user = (User) simplePrincipalCollection.getPrimaryPrincipal();
// 6. 清除当前用户以前登录时保存的session会话
if (loginName.equals(user.getUserName()) && !onlineSession.getId().equals(currentUserSessionId)) {
sessionManager.getSessionDAO().delete(onlineSession);
System.out.println("清理用户["+loginName+"],SessionId为["+onlineSession.getId()+"]的Session信息!");
}
}
} else {
System.out.println("无可清理用户信息~");
}
}
方法二:传入的参数是userName字符串
登录后复制
/**
* @功能描述: 单用户登录,清除当前用户以前登录时保存的session会话
* @param loginName
*/
public void singleUseLogin(HttpServletRequest request,String loginName){
// 1.获取当前用户sessionId
String currentUserSessionId = request.getSession().getId();
// 2.获取shiro的sessionManager
DefaultWebSecurityManager securityManager = (DefaultWebSecurityManager) SecurityUtils.getSecurityManager();
DefaultWebSessionManager sessionManager = (DefaultWebSessionManager)securityManager.getSessionManager();
// 3.获取所有已登录用户的session列表
Collection<Session> sessions = sessionManager.getSessionDAO().getActiveSessions();
// 处理方法一:UserRalm中传入的是userName使用此方法
String onlineSessionKey = "";
for(Session onlineSession:sessions){
// 4.获取已登录用户的session的key值
onlineSessionKey = String.valueOf(onlineSession.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY));
// 5.清除当前用户以前登录时保存的session会话
System.out.println(onlineSession.getId()+"------" + onlineSessionKey);
if (onlineSessionKey.equals("null")) {
sessionManager.getSessionDAO().delete(onlineSession);
} else if (loginName.equals(onlineSessionKey) && !onlineSession.getId().equals(currentUserSessionId)) {
sessionManager.getSessionDAO().delete(onlineSession);
}
}
}
方法二,优化版
/**
* @功能描述: 单用户登录,清除当前用户以前登录时保存的session会话
* @param loginName
*/
public void singleUseLogin(String loginName){
// 1.获取当前用户sessionId
String currentUserSessionId = SecurityUtils.getSubject().getSession().getId().toString();
// 2.获取当前用户
User user = (User) SecurityUtils.getSubject().getPrincipal();
// 3.获取shiro的sessionManager
DefaultWebSecurityManager securityManager = (DefaultWebSecurityManager) SecurityUtils.getSecurityManager();
DefaultWebSessionManager sessionManager = (DefaultWebSessionManager)securityManager.getSessionManager();
// 4.获取所有已登录用户的session列表
Collection<Session> sessions = sessionManager.getSessionDAO().getActiveSessions();
if (sessions.size() > 1) {
System.out.println("仅允许单用户登录,开始清理遗留用户信息~");
for(Session onlineSession:sessions){
// 5. 清除当前用户以前登录时保存的session会话
if (loginName.equals(user.getUserName()) && !onlineSession.getId().equals(currentUserSessionId)) {
sessionManager.getSessionDAO().delete(onlineSession);
System.out.println("清理用户["+loginName+"],SessionId为["+onlineSession.getId()+"]的Session信息!");
}
}
} else {
System.out.println("无可清理用户信息~");
}
}
# 这个的底层的作者还在继续深入研究 中,想看看能不能仿照写一个进行学习
本文详细探讨了Apache Shiro框架如何实现单用户登录功能,通过清理旧Session来确保同一用户只能有一个在线会话。代码示例展示了如何获取并遍历所有活跃Session,删除除当前用户Session外的其他Session,以实现单点登录的效果。方法一是通过User对象,方法二是通过userName字符串,两种方式都确保了用户登录的唯一性。

1532

被折叠的 条评论
为什么被折叠?



