如下,找到session中的信息删除即可,按照这个方式试了下。基本可用
在多台服务器部署时,前提必须实现session共享。
/**
* 登录认证
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//获取用户的输入的账号.
String username = (String)token.getPrincipal();
//通过username从数据库中查找 User对象,如果找到,没找到.
//实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法
LoginUser userInfo = loginUserBiz.getByName(username);
if(null==userInfo){
return null;
}
//2.处理一个账号异地登录的问题,后期用户量上来需要做优化,比如登录用cas
DefaultWebSecurityManager securityManager = (DefaultWebSecurityManager) SecurityUtils.getSecurityManager();
DefaultWebSessionManager sessionManager = (DefaultWebSessionManager)securityManager.getSessionManager();
//获取当前已登录的用户session列表
Collection<Session> sessions = sessionManager.getSessionDAO().getActiveSessions();
for(Session session:sessions){
//查找是否有当前登录账户的记录,有就清除该用户以前登录时保存的session
Object obj = session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
if(null!=obj){
if(obj instanceof SimplePrincipalCollection){
//强转
SimplePrincipalCollection spc = (SimplePrincipalCollection)obj;
LoginUser user = new LoginUser();
BeanUtils.copyProperties(spc.getPrimaryPrincipal(),user);
//判断用户,匹配用户ID。
if(userInfo.getId().equals(user.getId())){
sessionManager.getSessionDAO().delete(session);
}
}
}
}
//创建认证
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
userInfo, //用户信息
userInfo.getPassword(), //密码
ByteSource.Util.bytes(userInfo.getSalt()),//passsword=MD5(pass+salt)
getName() //realm name
);
return authenticationInfo;
}
DEBUG信息如下,也可以把比对的对象转换后在比对登录id
可以看到上面的代码是找到登录的账号,删除了其session,然后重新创建认证。
当然我们不重写shiro的登录认证方法,在业务层也是可以实现的。首先查询当前登录账号是否存在,存在直接调用SecurityUtils.getSubject().logout()退出登录,然后再调用一次登录,只是这样更复杂而已。