`
Ring风
  • 浏览: 63462 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Spring security扩展自定义会话管理

 
阅读更多

控制用户重复登陆 

springsecurity有控制单账号只能在一个地方登陆的功能,后登陆用户将踢掉前登陆用户;或者限制账号重复登陆,一个账号没有退出,另外一个人想用这个账号就登陆不上。 

现在我想根据原有的这些功能参考,做一个管理员可以将某正在session中的用户踢出系统的功能。便于管理员修改了登陆用户的权限或者部门设置后,强制让该用户重新登录。 

主要参考了如下两篇文章: 
http://www.family168.com/oa/springsecurity/html/ch214-smart-concurrent.html 
http://www.blogjava.net/beyondwcm/archive/2009/05/08/269545.html 

主要涉及的类如下(我自己的山寨理解): 
HttpSessionEventPublisher             监听session创建和销毁 
ConcurrentSessionFilter                  每次有http请求时校验,看你当前的session是否是过期的 
SessionRegistryImpl                       存放session中的信息,并做处理 
ConcurrentSessionControllerImpl     用户登入登出的控制 
SessionInformation       存储session中信息的model 

先实现springsecurity文档上的,限制用户重复登陆,后登陆用户将前登陆用户冲掉 ,只需要在xml中配置如下: 
<authentication-manager alias="authenticationManager" 
session-controller-ref="currentController" /> 
<beans:bean id="concurrentSessionFilter"   class="org.springframework.security.concurrent.ConcurrentSessionFilter"> 
<custom-filter position="CONCURRENT_SESSION_FILTER" /> 
<beans:property name="sessionRegistry" ref="sessionRegistry" /> 
<!-- 踢出的用户转向的页面--> 
<beans:property name="expiredUrl" value="/user/user.action" /> 
<beans:property name="logoutHandlers"> 
   <beans:list> 
    <beans:bean class="org.springframework.security.ui.logout.SecurityContextLogoutHandler" /> 
    <beans:bean 
     class="org.springframework.security.ui.rememberme.TokenBasedRememberMeServices"> 
     <beans:property name="key" value="e37f4b31-0c45-11dd-bd0b-0800200c9a66"/> 
     <beans:property name="userDetailsService" ref="userDetailsService"/> 
    </beans:bean> 
   </beans:list> 
</beans:property> 
</beans:bean> 
<beans:bean id="sessionRegistry"   class="org.springframework.security.concurrent.SessionRegistryImpl" /> 
<beans:bean id="currentController" 
class="org.springframework.security.concurrent.ConcurrentSessionControllerImpl"> 
<beans:property name="sessionRegistry" ref="sessionRegistry" /> 
<!-- true限制不允许第二个用户登录,false第二个登陆用户踢掉前一个登陆用户 --> 
<beans:property name="exceptionIfMaximumExceeded" value="false" /> 
<!-- 等第二种情况是,允许同时多少个用户同时登陆 --> 
<beans:property name="maximumSessions" value="2"/> 
</beans:bean> 

其中web.xml还需要添加: 
<!-- 登入和登出时对SessionRegistryImpl进行处理 --> 
<listener> 
<listener-class>org.springframework.security.ui.session.HttpSessionEventPublisher</listener-class> 
</listener> 

 

提供管理员调用踢出用户 

配置文件基本上和(一)比没有做什么修改,只是不限制用户用同一账号登陆,所以配置maximumSessions为-1 
<beans:bean id="currentController" 
class="org.springframework.security.concurrent.ConcurrentSessionControllerImpl"> 
<beans:property name="sessionRegistry" ref="sessionRegistry" /> 
<beans:property name="exceptionIfMaximumExceeded" 
   value="false" /> 
<beans:property name="maximumSessions" value="-1"/> 
</beans:bean> 

其实要实现列表当前登陆的用户,并踢出用户,就是调用springsecurity的 
org.springframework.security.concurrent.SessionRegistryImpl 
就可以满足要求了,当然,用这个类来做踢出用户的功能,不是很好,不过也懒得去动这个源码了,由于mini-web的示例是struts2的,所以我就简单的写了个Action去调用这个类来操作,如果要用到公司的项目中,那还要放到controller里面去才行,SessionAction.java: 
package org.springside.examples.miniweb.web.user; 
import java.util.ArrayList; 
import java.util.List; 
import org.apache.struts2.config.ParentPackage; 
import org.apache.struts2.config.Result; 
import org.apache.struts2.config.Results; 
import org.apache.struts2.dispatcher.ServletActionRedirectResult; 
import org.springframework.security.concurrent.SessionInformation; 
import org.springframework.security.concurrent.SessionRegistry; 
import org.springside.modules.web.struts2.CRUDActionSupport; 
import org.springside.modules.web.struts2.SimpleActionSupport; 
@ParentPackage("default") 
@Results( { @Result(name = CRUDActionSupport.RELOAD, value = "/session", type = ServletActionRedirectResult.class) }) 
public class SessionAction extends SimpleActionSupport { 
private static final String RELOAD = "reload"; 
private static final long serialVersionUID = 8071034786218297672L; 
private String loginId; 
private SessionRegistry sessionRegistry; 
List<String> loginIds; 
           //默认方法 
public String execute() throws Exception { 
   return list(); 

           //列表当前登录的用户的loginIds 
public String list() throws Exception { 
   Object[] loginIds_obj = sessionRegistry.getAllPrincipals(); 
   if (loginIds_obj != null && loginIds_obj.length > 0) { 
    loginIds = new ArrayList<String>(loginIds_obj.length); 
    for (int i = 0; i < loginIds_obj.length; i++) { 
     loginIds.add((String) loginIds_obj[i]); 
    } 
   } 
   return SUCCESS; 

//根据传入的loginId,踢出某用户 
public String destroy() throws Exception { 
   SessionInformation[] sessions_arrs = sessionRegistry.getAllSessions( 
     loginId, false); 
   if (sessions_arrs != null && sessions_arrs.length > 0) { 
    for (int i = 0; i < sessions_arrs.length; i++) { 
     sessions_arrs[i].expireNow(); 
     // sessionRegistry.removeSessionInformation(sessions_arrs[i].getSessionId()); 
    } 
   } 
   return RELOAD; 

public String getLoginId() { 
   return loginId; 

public void setLoginId(String loginId) { 
   this.loginId = loginId; 

public List<String> getLoginIds() { 
   return loginIds; 

public void setLoginIds(List<String> loginIds) { 
   this.loginIds = loginIds; 

public void setSessionRegistry(SessionRegistry sessionRegistry) { 
   this.sessionRegistry = sessionRegistry; 



分享到:
评论
2 楼 Ring风 2014-10-08  
错误信息是什么。。。
1 楼 MrwenQ 2014-09-16  
你好楼主,我有个问题想问 为什么我写自定义filter的时候总是报错 启动就报错 能给我讲解下吗?

相关推荐

Global site tag (gtag.js) - Google Analytics