Cometd,春季安全性:当前已通过身份验证的用户在侦听器内部不可用

时间:2018-10-12 12:13:50

标签: java spring spring-security comet cometd

我正在一个Spring-MVC项目中,我正在使用Spring-security进行身份验证和授权。除此之外,我正在使用Cometd库通过websocket发送消息。在侦听器中收到消息后,当我尝试获取当前经过身份验证的用户时,该消息始终为null。

如何确保Cometd atleast中的每个请求都包含Spring-security识别所需的JSESSIONID?

或者Spring-security中有一些设置可以使之成为可能。

当我向上看时,有很多用户面临此问题,但是没有确定的答案或有用的代码。

测试代码:

  @Listener(value = "/service/testlistener/{id}")
    public void testlistener(ServerSession remote,
                             ServerMessage message, @Param("id") String id) {
        try {            
          Person user = this.personService.getCurrentlyAuthenticatedUser();
            Map<String, Object> data = message.getDataAsMap();
           System.out.println("currentlyAuthenticatedUser: " + user + " \nTransmitted Data in map:" + data.get("name"));
            Map<String, Object> output = new HashMap<>();
            output.put("name", user.getFirstName());
            ServerChannel serverChannel = bayeux.createChannelIfAbsent("/person/" + id).getReference();
            serverChannel.setPersistent(false);
            serverChannel.publish(serverSession, output);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

cometd.js:

 var connectionIntervall = null;
    var onlineElement = document.getElementById("browser-online");
    var cometd = $.cometd;
    cometd.configure({
        url: navigationController.generateCometDUrl(),
        logLevel: 'error',
        stickyReconnect: false,
        appendMessageTypeToURL: false,
        requestHeaders : navigationController.generateCometDHeaders()
    });

    var connects = 0;

    cometd.addListener('/meta/handshake', _metaHandshake);
    cometd.addListener('/meta/connect', _metaConnect);
    cometd.websocketEnabled = true;

    cometd.handshake();

1 个答案:

答案 0 :(得分:1)

解决方案: -彗星4.0.2 -春天4.3.9.RELEASE -Spring Security 4.1.0.RELEASE

在我的项目中,从“长池”连接切换为“ websocket”连接时,我们遇到了类似的问题。为了澄清-一个区别-我们仅在“握手”期间使用“用户上下文”。

使用“长缓冲池”时,Spring正确地解释了带有JSESSIONID的Cookie,我们正在“用户上下文”中工作。切换到“ websocket”后,看起来就像在运行消息接收代码之前丢失了“用户上下文”。

我们找不到合适的解决方案-在我看来,以下代码只是一个hack。但这对我们有用。

import org.cometd.bayeux.server.BayeuxServer;
import org.cometd.bayeux.server.ServerMessage;
import org.cometd.bayeux.server.ServerSession;
import org.cometd.server.DefaultSecurityPolicy;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;

public class BayeuxAuthenticator extends DefaultSecurityPolicy implements ServerSession.RemoveListener {

    // (...)

    @Override
    public boolean canHandshake( BayeuxServer server, ServerSession session, ServerMessage message ) {
        SecurityContextHolder.getContext().setAuthentication( ( UsernamePasswordAuthenticationToken ) message.getBayeuxContext().getUserPrincipal() );
        String user = securityService.getUserName();
        // (...)

        return true;
    }

    // (...)
}

以下哪一行是最重要的

SecurityContextHolder.getContext().setAuthentication( ( UsernamePasswordAuthenticationToken ) message.getBayeuxContext().getUserPrincipal() );

编辑2:

我们正在接收来自

的数据
String user = securityService.getUserName();

其中securityService是受Spring @Secured保护的Spring @Service(/ *预期角色* /)。 (@Secured注释在设置上下文之前会向我们生成授权异常)

内部有上下文读取和用户数据:

SecurityContextHolder.getContext().getUserPrincipal().getName()

但是,老实说,如果您仅需要“用户主体”,则可以从以下内容中读取内容:

message.getBayeuxContext().getUserPrincipal() // instanceof java.security.Principal

在我们的案例中是

org.springframework.security.authentication.UsernamePasswordAuthenticationToken

也许您是不同的子类?

为了澄清-在启动Web套接字连接期间,我们在请求中传递了具有正确JSESSIONID的Cookie。

WebSocket连接请求:

Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9,pl;q=0.8
Cache-Control: no-cache
Connection: Upgrade
Cookie: XSRF-TOKEN=<some token>; Idea-<some token>; lastOpenTab=sourcing/content; io=<some token>; BAYEUX_BROWSER=<some token>; JSESSIONID=<some token>
Host: localhost:8090
Origin: http://localhost:8090
Pragma: no-cache
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Key: NTtWtXAL8ReIB0LjvI2G0g==
Sec-WebSocket-Version: 13
Upgrade: websocket
User-Agent: Mozilla/5.0 ...
相关问题