简体   繁体   English

春季安全性,如何使用户的所有会话期满

[英]spring security, how to expire all sessions of a user

I have to solve the following scenario, in a Spring Security 3.2.5-RELEASE with Spring Core 4.1.2-RELEASE application running Java 1.7 on wildfly 8.1. 我必须在带有在Wildfly 8.1上运行Java 1.7的Spring Core 4.1.2-RELEASE应用程序的Spring Security 3.2.5-RELEASE解决以下情况。

  1. user 'bob' logs in 用户“ bob”登录
  2. and Admin deletes 'bob' 管理员删除“ bob”
  3. if 'bob' logs out, he can't log in. again but he`s current session remains active. 如果“ bob”注销,则他无法再次登录。但是他的当前会话仍处于活动状态。
  4. i want to kick 'bob' out 我想把鲍勃踢出去

     //this doesn't work for (final SessionInformation session : sessionRegistry.getAllSessions(user, true)) { session.expireNow(); } 
  1. add application event listener to track HttpSessionCreatedEvent and HttpSessionDestroyedEvent and register it as an ApplicationListener and maintain a cache of SessionId to HttoSession. 添加应用程序事件侦听器以跟踪HttpSessionCreatedEventHttpSessionDestroyedEvent并将其注册为ApplicationListener并维护SessionId到HttoSession的缓存。
  2. (optional) add your own ApplicationEvent class AskToExpireSessionEvent - (可选)添加您自己的ApplicationEvent类AskToExpireSessionEvent
  3. in you user management service add dependencies to SessionRegistry and ApplicationEventPublisher so that you could list through the currently active user sessions and find the ones (cause there could be many) which are active for the user you are looking for ie 'bob' 在您的用户管理服务中,将依赖SessionRegistry添加到SessionRegistryApplicationEventPublisher以便您可以列出当前活动的用户会话,并找到正在寻找的用户活动的会话(因为可能有很多),即“ bob”
  4. when deleting a user dispatch an AskToExpireSessionEvent for each of his sessions. 删除用户时,为每个会话分配AskToExpireSessionEvent
  5. use a weak reference HashMap to track the sessions 使用弱引用HashMap跟踪会话

user service: 用户服务:

     @Service
     public class UserServiceImpl implements UserService {

      /** {@link SessionRegistry} does not exists in unit tests */
      @Autowired(required = false)
      private Set<SessionRegistry> sessionRegistries;


      @Autowired
      private ApplicationEventPublisher publisher;


     /**
      * destroys all active sessions.
      * @return <code>true</code> if any session was invalidated^
      * @throws IllegalArgumentException
      */
      @Override
      public boolean invalidateUserByUserName(final String userName) {
              if(null == StringUtils.trimToNull(userName)) {
                      throw new IllegalArgumentException("userName must not be null or empty");
              }
              boolean expieredAtLeastOneSession = false;
              for (final SessionRegistry sessionRegistry : safe(sessionRegistries)) {
                      findPrincipal: for (final Object principal : sessionRegistry.getAllPrincipals()) {
                              if(principal instanceof IAuthenticatedUser) {
                                      final IAuthenticatedUser user = (IAuthenticatedUser) principal;
                                      if(userName.equals(user.getUsername())) {
                                              for (final SessionInformation session : sessionRegistry.getAllSessions(user, true)) {
                                                      session.expireNow();
                                                      sessionRegistry.removeSessionInformation(session.getSessionId());
                                                      publisher.publishEvent(AskToExpireSessionEvent.of(session.getSessionId()));
                                                      expieredAtLeastOneSession = true;
                                              }
                                              break findPrincipal;
                                      }
                              } else {
                                      logger.warn("encountered a session for a none user object {} while invalidating '{}' " , principal, userName);
                              }
                      }
              }
              return expieredAtLeastOneSession;
      }

     }

Application event: 申请活动:

     import org.springframework.context.ApplicationEvent;

     public class AskToExpireSessionEvent extends ApplicationEvent {

             private static final long serialVersionUID = -1915691753338712193L;

             public AskToExpireSessionEvent(final Object source) {
                     super(source);
             }

             @Override
             public String getSource() {
                     return (String)super.getSource();
             }


             public static AskToExpireSessionEvent of(final String sessionId) {
                     return new AskToExpireSessionEvent(sessionId);
             }
     }

http session caching listener: http会话缓存侦听器:

     import java.util.Map;
     import java.util.WeakHashMap;

     import javax.servlet.http.HttpSession;

     import org.slf4j.Logger;
     import org.slf4j.LoggerFactory;
     import org.springframework.beans.factory.annotation.Autowired;
     import org.springframework.context.ApplicationListener;
     import org.springframework.security.web.session.HttpSessionCreatedEvent;
     import org.springframework.security.web.session.HttpSessionDestroyedEvent;
     import org.springframework.stereotype.Component;

     import com.cb4.base.service.event.AskToExpireSessionEvent;


     @Component
     public class HttpSessionCachingListener {

             private static final Logger logger = LoggerFactory.getLogger(HttpSessionCachingListener.class);

             private final Map<String, HttpSession> sessionCache = new WeakHashMap<>();

             void onHttpSessionCreatedEvent(final HttpSessionCreatedEvent event){
                     if (event != null && event.getSession() != null && event.getSession().getId() != null) {
                             sessionCache.put(event.getSession().getId(), event.getSession());
                     }
             }

             void onHttpSessionDestroyedEvent(final HttpSessionDestroyedEvent event){
                     if (event != null && event.getSession() != null && event.getSession().getId() != null){
                             sessionCache.remove(event.getSession().getId());
                     }
             }

             public void timeOutSession(final String sessionId){
                     if(sessionId != null){
                             final HttpSession httpSession = sessionCache.get(sessionId);
                             if(null != httpSession){
                                     logger.debug("invalidating session {} in 1 second", sessionId);
                                     httpSession.setMaxInactiveInterval(1);
                             }
                     }
             }

             @Component
             static class HttpSessionCreatedLisener implements ApplicationListener<HttpSessionCreatedEvent> {

                     @Autowired
                     HttpSessionCachingListener parent;

                     @Override
                     public void onApplicationEvent(final HttpSessionCreatedEvent event) {
                             parent.onHttpSessionCreatedEvent(event);
                     }
             }

             @Component
             static class HttpSessionDestroyedLisener implements ApplicationListener<HttpSessionDestroyedEvent> {

                     @Autowired
                     HttpSessionCachingListener parent;

                     @Override
                     public void onApplicationEvent(final HttpSessionDestroyedEvent event) {
                             parent.onHttpSessionDestroyedEvent(event);
                     }
             }

             @Component
             static class AskToTimeOutSessionLisener implements ApplicationListener<AskToExpireSessionEvent> {

                     @Autowired
                     HttpSessionCachingListener parent;

                     @Override
                     public void onApplicationEvent(final AskToExpireSessionEvent event) {
                             if(event != null){
                                     parent.timeOutSession(event.getSource());
                             }
                     }
             }

     }

Using java config add the following code in your class extending WebSecurityConfigurerAdapter : 使用java config在您的类中添加以下代码,以扩展WebSecurityConfigurerAdapter

      @Bean
public SessionRegistry sessionRegistry( ) {
    SessionRegistry sessionRegistry = new SessionRegistryImpl( );
    return sessionRegistry;
}

@Bean
public RegisterSessionAuthenticationStrategy registerSessionAuthStr( ) {
    return new RegisterSessionAuthenticationStrategy( sessionRegistry( ) );
}

and add the following in your configure( HttpSecurity http ) method: 并在您的configure(HttpSecurity http)方法中添加以下内容:

    http.sessionManagement( ).maximumSessions( -1 ).sessionRegistry( sessionRegistry( ) );
    http.sessionManagement( ).sessionFixation( ).migrateSession( )
            .sessionAuthenticationStrategy( registerSessionAuthStr( ) );

Also, set the registerSessionAuthenticationStratergy in your custom authentication bean as follows: 另外,在自定义身份验证Bean中设置registerSessionAuthenticationStratergy ,如下所示:

    usernamePasswordAuthenticationFilter
            .setSessionAuthenticationStrategy( registerSessionAuthStr( ) );

NOTE: Setting registerSessionAuthenticationStratergy in your custom authentication bean causes the prinicpal list to be populated and hence when you try to fetch the list of all prinicipals from sessionRegistry ( sessionRegistry.getAllPrinicpals() ), the list is NOT empty. 注意:在自定义身份验证Bean中设置registerSessionAuthenticationStratergy会导致填充主列表,因此,当您尝试从sessionRegistry( sessionRegistry.getAllPrinicpals() )获取所有主列表时,该列表不为空。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM