spring security3.0控制多个用户账号同时登录和管理员踢出用户(原创)

        声明一下,这篇文章不是基于acegi  spring security2.0写的,  我发现很多文章都是基于老版本写的,  并不适用最新版。

下面跟大家分享一下在spring security3.0里如何正宗的做法达到控制多个账号请求的经验。

 

步骤1

下面只贴出关键部分, 为了不影响阅读。

 

注意: 不需要配置 SessionRegistry 等bean( 假设你其他地方不用到的话, 如果用到需要在

加上一个属性

 

在做某个管理员踢出一个账号的时候, SessionRegistry 这个bean是需要用到的。 写法如下:

@RequestMapping(value = "logout.html") public String logout(String sessionId, String sessionRegistryId, String name, HttpServletRequest request, ModelMap model){ List userList=sessionRegistry.getAllPrincipals(); for(int i=0; i sessionInformationList = sessionRegistry.getAllSessions(userTemp, false); if (sessionInformationList!=null) { for (int j=0; j

 

 

有时候按文档和网上配置出来是很华丽, 可事实有时候就是没有如期运行。

我打开火狐  360浏览器, 还是等两个账号同时登录。

无奈之下把源码下下载剖析(常干的事儿, 喜欢捣腾这些东西)

 

判断重复的类是ConcurrentSessionControlStrategy.java下的

checkAuthenticationAllowed这个函数的

final List sessions = sessionRegistry.getAllSessions(authentication.getPrincipal(), false); int sessionCount = sessions.size();

最重要的一句话是:

sessionInformationList.get(j).expireNow();
这句强制T出了用户, (设置为过期)

如果想彻底删除, 加上

sessionRegistry.removeSessionInformation(sessionInformationList.get(j).getSessionId());

即可,

这样使用getAllPrincipals  则获取不到被T出的用户了,  其实原理不是直接删除User对象, 只结束了它的sessionId,

因为这个User可能不止对应着1个sessionId

 

 

我发现, 无论我怎么配置,  sessionCount老是烦人的 0。    即使我手动配置了ConcurrentSessionControlStrategy这个bean也没用(默认会自己调的)

 

无奈中想自己写一个自定义的计数器控制, 但细想它这东西不至于这个小问题都出这么大的漏洞吧?

 

现在的问题是:

如何让 int sessionCount = sessions.size();  这句在第二个账号登陆的时候不为0。

 

于是我进入了sessionRegistry.getAllSessions(authentication.getPrincipal(), false);  这个函数。

 

也就是SessionRegistryImpl.java

 

    public List getAllSessions(Object principal, boolean includeExpiredSessions) {
        final Set sessionsUsedByPrincipal = principals.get(principal);

 

这个函数是通过在一个HashMap里拿到key value的。

 

而principals的声明这样写。

 

private final Map> principals = Collections.synchronizedMap(new HashMap>());

 

 

现在的问题变为了:

如何让两个principal  ,  也就是User, 也就是

public UserDetails loadUserByUsername(String username)

 

两次登陆的时候返回的是同一个对象。

 

那么如何做到两次在不同浏览器登陆的时候返回的是同一个User?

 

答案是java的基础, equal   hashcode方法重写。

 

在User对象里添加以下方法:

 

public boolean equals(Object object) { if (object instanceof BaseObject) { if (this.id.equals(((BaseObject) object).getId())) return true; } return false; } public int hashCode(){ return this.id.hashCode(); }

 

 涉及这方面的基础请参考   http://blog.csdn.net/willielee/archive/2010/08/11/5804463.aspx

 

我就不浪费CSDN的硬盘空间了, 不过还是得贴出最后一句话:

HashMap的key判断key是否相等也是从hashcode和equals是否相等判断

 

 从上面可以看出, 我们之前登陆的用户是存在    Map> principals  的。

这个存储结构是,  一个User  对应多个Set集合的sessionId。

所以要判断用户是否已存在登陆的了, 当然要重写这2个方法。

 

 

你可能感兴趣的:(Spring)