用于Spring Security和/或Spring BlazeDS集成的会话管理(和查杀)的集中系统 [英] Centralized system for session management (and killing) for Spring Security and/or Spring BlazeDS Integration

查看:141
本文介绍了用于Spring Security和/或Spring BlazeDS集成的会话管理(和查杀)的集中系统的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很难实现客户要求的功能。简而言之,他们希望能够通过管理员方面退出他们选择的任何客户。该应用程序使用Flex作为前端技术并通过AMF访问服务器。服务器端正在使用Spring Security和Spring BlazeDS Integration。

I'm having a hard time implementing a feature that our customer requests. In short they want to be able to logout any customer of their choosing out of the application via the admin side. The application is using Flex as a front end technology and accessing server via AMF. Server side is using Spring Security and Spring BlazeDS Integration.

基本上问题是:Spring Security和/或Spring BlazeDS Integration是否提供任何集中式会话管理系统(并且可以查杀) ) 盒子外面?

Basically the question is: does Spring Security and/or Spring BlazeDS Integration offer any centralized system for session management (and killing) out-of-the-box?

出于概念验证的目的,我试图注销所有用户并使用以下代码终止所有会话:

For proof-of-concept purposes I have tried to logout all users and kill all sessions with following code:

package xxx.xxx.xxx;

import java.util.List;

import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.session.SessionInformation;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.userdetails.User;

import flex.messaging.MessageBroker;
import flex.messaging.security.LoginCommand;

public class SessionServiceImpl {
    private static final Log log = LogFactory.getLog(SessionServiceImpl.class);

    private SessionRegistry sessionRegistry;
    private MessageBroker messageBroker;

    public SessionRegistry getSessionRegistry() {
        return sessionRegistry;
    }

    @Autowired
    public void setSessionRegistry(SessionRegistry sessionRegistry) {
        log.debug("sessionregistry set");
        this.sessionRegistry = sessionRegistry;
    }    

    public MessageBroker getMessageBroker() {
        return messageBroker;
    }

    @Autowired
    public void setMessageBroker(MessageBroker messageBroker) {
        log.debug("messagebroker set");
        this.messageBroker = messageBroker;
    }

    public void logoutUser(String userName) {
        log.debug("Logging out user by username: "+userName);
        List<Object> principals = null;
        if(sessionRegistry != null){
            principals = sessionRegistry.getAllPrincipals();
        }else{
            log.debug("sessionRegistry null");
        }

        if(principals != null){
            for (Object object : principals) {
                User user = (User)object;

                // get single users all sessions
                List<SessionInformation> sessions = sessionRegistry.getAllSessions(user, false);
                log.debug("Sessions list size: "+sessions.size());


                if(messageBroker != null){
                    LoginCommand command = messageBroker.getLoginManager().getLoginCommand();
                    UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(user, user.getPassword());
                    command.logout(usernamePasswordAuthenticationToken);

                    for (SessionInformation sessionInformation : sessions) {
                        log.debug(ReflectionToStringBuilder.toString(sessionInformation));
                        sessionInformation.expireNow();
                        sessionRegistry.removeSessionInformation(sessionInformation.getSessionId());
                    }

                }else{
                    log.debug("messageBroker null");
                }

                if(object != null){
                    log.debug(ReflectionToStringBuilder.toString(object));
                }else{
                    log.debug("object null");
                }

            }
        }else{
            log.debug("principals null");
        }
    }
}

不幸的是上面的代码没有工作。据我所知,这是因为两件事:

Unfortunately the above code does not work. As far as I can tell this is because two things:

A)LoginCommand不是应用程序范围,而是绑定到当前会话,因此它将尝试仅注销当前会话(管理员正在使用的会话)并且忘记了其他会话

A) LoginCommand is not "application wide" but tied to the current session, therefore it will try to logout only current session (the session the admin is using) and is oblivious of other sessions

B)sessionInformation.expireNow()尝试使会话失效但是如果用户设法制作一个会话在会话失效之前的请求,会话没有被销毁

B) sessionInformation.expireNow() tries to expire the session but if user manages to make a request before session gets invalidated, the session is not destroyed

从文档中我可以看到会话可以被session.invalidate()直接无效,但似乎我有无法访问所有会话对象。

From the documentation I can see that session could be directly invalidated by session.invalidate(), but it seems I have no way to access all session objects.

实现此类功能的最快或最智能的方式是什么?

What is the fastest or smartest way to implement this kind of feature?

最好的问候,
Jukka

Best regards, Jukka

推荐答案

我花了很长时间试图达到同样的目的。

I've spent a long time trying to achieve the same thing.

最后,我想我已经解决了。首先删除代码的LoginCommand部分,因为正如你猜测的那样,它与启动删除的用户有关 - 在你的情况下是管理员 - 而不是目标用户的会话。

In the end, I think I've resolved it. First remove the LoginCommand section of your code, because as you surmise, it relates to the user initiating the delete - in your case, the admin - and not the session of the target user.

然后,尝试删除它:

sessionRegistry.removeSessionInformation(sessionInformation.getSessionId());

由于某种原因,这似乎取消了到期而没有实际停止进一步的请求被授予。没有印象!

For some reason this appears to cancel out the expiry without actually stopping further requests being granted. Unimpressive!

如果它不起作用,那么在干预这个问题的过程中,我有另一个想法,我没有带来结果。这是为每个请求添加一个过滤器,并在那里检查会话到期时间。

If it doesn't work, then in the midsts of meddling with this, I had another idea which I didn't bring to fruition. This is to add a filter for every request, and check for session expiry in there.

所以,在您的安全XML中:

So, in your security XML:

<beans:bean id="sessionFilter" class="my.package.CustomSessionFilter"/>
<beans:bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl"/>

<http use-expressions="true" auto-config="true">
    <custom-filter after="CONCURRENT_SESSION_FILTER" ref="sessionFilter"/>
    <session-management>
        <concurrency-control session-registry-ref="sessionRegistry"/>
    </session-management>
...

然后上课:

@Component
public class CustomSessionFilter extends OncePerRequestFilter
{
/**The session registry.*/
@Autowired
private SessionRegistry sessionRegistry;

@Override
protected void doFilterInternal( HttpServletRequest request,
                                 HttpServletResponse response,
                                 FilterChain filterChain )
    throws ServletException,
        IOException
{

    //get session for the user, and if expired, do something (e.g. redirect)

    //else...
    filterChain.doFilter(request, response);
}
}

我发现这是成功调用的请求依据。希望你不需要上面的内容,因为它是一种不太优雅的方式来实现框架应该为你做的事情。

I found this to be successfully called on a per-request basis. Hopefully you don't need the above, as it's an inelegant way to achieve something the framework ought to be doing for you.

这篇关于用于Spring Security和/或Spring BlazeDS集成的会话管理(和查杀)的集中系统的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆