代码之家  ›  专栏  ›  技术社区  ›  We are Borg

Cometd,Spring security:当前已验证的用户在侦听器中不可用

  •  0
  • We are Borg  · 技术社区  · 7 年前

    我在一个springmvc项目中使用springsecurity进行身份验证和授权。除此之外,我还使用Cometd库通过websockets发送消息。在侦听器中接收到消息后,当我尝试获取当前经过身份验证的用户时,它总是空的。

    如何确保Cometd中的每个请求至少都包含Spring安全性用于标识的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();
            }
        }
    

    Comed.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 回复  |  直到 7 年前
        1
  •  1
  •   Łukasz Kotyński    7 年前

    解决方案: -CometD 4.0.2版 -弹簧4.3.9.释放 -Spring Security 4.1.0.发布

    通过使用“长池”,Spring正确解释了带有JSESSIONID的Cookie,我们在“用户上下文”中工作。切换到“websocket”后,就在运行消息接收代码之前,“用户上下文”似乎丢失了。

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

    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(@安全批注在设置上下文之前生成us授权异常)

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

    但老实说,如果您只需要“用户主体”,那么从以下方面阅读就足够了:

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

    在我们的案例中是

    org.springframework.security.authentication.UsernamePasswordAuthenticationToken
    

    也许在你的情况下它是不同的子类?

    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 ...