杀死服务器会话春天

Posted

技术标签:

【中文标题】杀死服务器会话春天【英文标题】:kill server sessions spring 【发布时间】:2016-04-20 08:26:32 【问题描述】:

我有一个基于 spring 框架的应用程序。 此应用程序允许每个用户进行 2 个多个会话。

<bean id="concurrencyFilter"
        class="org.springframework.security.web.session.ConcurrentSessionFilter">
        <property name="sessionRegistry" ref="sessionRegistry" />
        <property name="expiredUrl" value="/faces/pages/templates/error.xhtml" />
    </bean>

    <bean id="sessionRegistry"
        class="org.springframework.security.core.session.SessionRegistryImpl" />

    <bean id="sas"
        class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
        <constructor-arg>
            <list>
                <bean
                    class="org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy">
                    <constructor-arg ref="sessionRegistry" />
                    <property name="maximumSessions" value="2" />
                    <property name="exceptionIfMaximumExceeded" value="true" />
                </bean>
                <bean
                    class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy">
                </bean>
                <bean
                    class="org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy">
                    <constructor-arg ref="sessionRegistry" />
                </bean>
            </list>
        </constructor-arg>
    </bean>

我需要在使用第二个会话登录时,终止第一个会话。

我尝试使用 expireNow 方法,但 2 个会话保持活动状态。

        authenticate = authenticationManager
                .authenticate(new UsernamePasswordAuthenticationToken(username, password));
        if (authenticate.isAuthenticated()) 
            SecurityContextHolder.getContext().setAuthentication(authenticate);
            HttpServletRequest httpReq = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext()
                    .getRequest();
            HttpServletResponse httpResp = (HttpServletResponse) FacesContext.getCurrentInstance()
                    .getExternalContext().getResponse();

            sessionAuthenticationStrategy.onAuthentication(authenticate, httpReq, httpResp);

            final Collection<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
            final org.springframework.security.core.userdetails.User user = new org.springframework.security.core.userdetails.User(
                    username, password, grantedAuthorities);

            List<SessionInformation> sessions = sessionRegistry.getAllSessions(user, false);
            if (sessions.size() > 1) 
                sessionRegistry.getSessionInformation(sessions.get(0).getSessionId()).expireNow();


sessionRegistry.removeSessionInformation(sessions.get(0).getSessionId());
                

我怎样才能做到这一点!

谢谢。

【问题讨论】:

那你为什么首先想要两个并发会话......你基本上想要一个。 因为如果我只有1个会话,当我尝试在另一个地方登录时,我会被阻止,我需要当我在另一个地方登录时,关闭第一个会话并在第二个地方登录. 这取决于你的配置。 【参考方案1】:

请参阅Destroy a session of another user in spring。我希望这有帮助。专门在&lt;http&gt;部分寻找关于&lt;session-management ...&gt;的评论。

【讨论】:

【参考方案2】:

您可以尝试在登录代码之前添加以下内容。

这应该使该特定用户的会话 (authentication.getPrincipal()) 尚未过期,然后从 Spring Security 会话注册表中删除它们:

// expire and remove the user's sessions from sessionRegistry
List<Object> principals = sessionRegistry.getAllPrincipals();
for (Object principal : principals) 
    List<SessionInformation> sessions = sessionRegistry.getAllSessions(principal, true);
    for (SessionInformation sessionInfo : sessions) 
        if (authentication.getPrincipal().equals(sessionInfo.getPrincipal())) 
           if (!sessionInfo.isExpired()) sessionInfo.expireNow();
           sessionRegistry.removeSessionInformation(sessionInfo.getSessionId());
        
    

【讨论】:

以上是关于杀死服务器会话春天的主要内容,如果未能解决你的问题,请参考以下文章

杀死一个 postgresql 会话/连接

杀死分离的屏幕会话[关闭]

如何杀死一个/所有的 php 会话?

从用户会话进程打开在服务中创建的 JobObject

发件人应用程序在被杀死后如何恢复会话?

markdown 杀死会话