需求:实现同一个账号同一个时刻只能在一个IP浏览器登录,后者把前者挤掉线。
实现:通过shiro的session管理机制进行实现。
我的理解:shrio有一套sessionmanager的管理器,用来管理登录用户的session。不同的用户每次登录都会生成一个sessionid,保存在shrio框架中。我只需要实现根据登录用户的账号,判断正在登录的用户session是否已经存在于当前活跃的session列表中,如果存在的话,把那个session给删除,就可以成功实现将前一个登录的用户挤掉了。
这一段的逻辑代码是:
在自定义的ShiroJdbcRealm类中的doGetAuthenticationInfo--认证回调函数中加上:
long loginOnTime = new Date().getTime();
String tempSessionId = SecurityUtils.getSubject().getSession().getId().toString();//获取当前正在登录的用户的sessionID(已经登录了的,这是回调函数)
logger.info("正在登陆---登陆用户{}",tempSessionId);
AuthUserDetails userSession = null;
int count = 0;
if(authAccount != null){
//获取在线的session,获取当前所有活跃的用户;包括正在登陆的这个用户
Collection<Session> sessionCollection = sessionDAO.getActiveSessions();
for (Session session : sessionCollection){
// 获取simpleAuthenticationInfo的第一个参数的值
if(session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY) != null) {
//根据session build出一个subject
Subject subject = new Subject.Builder().session(session).buildSubject();
//循环遍历拿到已经登录的对象
userSession = (AuthUserDetails) subject.getPrincipal();
logger.info("缓存用户{}",userSession);
//判断已经登录的对象的code和现在正在登陆的code是否一致 ,这里的code用的是登录的账号
if (authAccount.getAuthUid().equals(userSession.getAuthUid())) {
//同一个账户登录的时候,除了当前正在登录的用户,其他的session都要移除。
if (session.getId()!=tempSessionId) {
sessionDAO.delete(session);//从活跃的session列表中移除同一个账号的其他session,除了当前正在登录的session
count++;
}
}
}
}
}
System.out.println("---------------------------"+count);
由于每一个http请求都会生成一个sessionID,所以实际上会移除很多session,但是都是这个账号的,所以无所谓了。
其中sessionDAO.getActiveSessions();这一行是会获取到当前活跃的所有的session(也就是没有过期的包括当前正在登录的用户的session)
shiro自己的配置文件讲解:
spring-shiro.xml,这里面就是用来定义bean,然后加载到其他定义bean中当前属性值进行使用,这样的话就不用自己实例化了,在代码里可以直接使用。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"
default-lazy-init="true">
<description>Shiro安全配置</description>
<!-- shiro cache using Redis
<bean id="shiroRedisManager" class="org.crazycake.shiro.RedisManager">
<property name=&