Spring mvc Websockets消息用户身份验证与Spring安全



我看过一些关于这个问题的帖子,但是似乎没有一个能直接回答这个问题。

后台,我已经安装了spring安全,在应用程序的其他部分正常工作和运行。我的用户名是"developer"

运行在Java 7, Glassfish 4, Spring 4上,使用Angular + StompJS

让我们在这里得到一些代码:

package com.myapp.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketBrokerConfig extends AbstractWebSocketMessageBrokerConfigurer {
    public final static String userDestinationPrefix = "/user/";
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/stomp").withSockJS().setSessionCookieNeeded(true);
    }
    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.setApplicationDestinationPrefixes("/app");
        //registry.enableStompBrokerRelay("/topic,/user");
        registry.enableSimpleBroker("/topic", "/user");
        registry.setUserDestinationPrefix(userDestinationPrefix);

    }

}

好的,现在这里有一个控制器,每3秒发送一次内容:

import org.springframework.messaging.simp.SimpMessagingTemplate;
…
@Autowired
private SimpMessagingTemplate messagingTemplate;
…
@Scheduled(fixedDelay = 3000)
public void sendStuff () 
{
    Map<String, Object> map = new HashMap<>();
    map.put(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON);
    System.out.print("Sending data! " + System.currentTimeMillis());
    //messagingTemplate.convertAndSend("/topic/notify", "Public: " + System.currentTimeMillis());
    messagingTemplate.convertAndSendToUser("developer", "/notify", "User: " + System.currentTimeMillis());
    messagingTemplate.convertAndSendToUser("notYou", "/notify", "Mr Developer Should Not See This: " + System.currentTimeMillis());
}

最后是JavaScript使用SockJS

    var client = new SockJS('/stomp');
    var stomp = Stomp.over(client);
    stomp.connect({}, function(s) {
        //This should work
        stomp.subscribe('/user/' + s.headers['user-name'] + '/notify', console.debug);
        //This SHOULD NOT
        stomp.subscribe('/user/notYou/notify', console.debug);
    });
    client.onclose = $scope.reconnect;

最后,pom.xml

    <dependency>
        <groupId>javax.websocket</groupId>
        <artifactId>javax.websocket-api</artifactId>
        <version>1.0</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-messaging</artifactId>
        <version>4.0.6.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-websocket</artifactId>
        <version>4.0.6.RELEASE</version>
    </dependency>

是这样的:

  1. 我可以在客户端和服务器之间产生美妙的来回通信
  2. 它快速
  3. messagingTemplate.convertAndSendmessagingTemplate.convertAndSendToUser

问题(如上所述):任何人都可以订阅其他用户的提要。

现在,这个问题还有其他一些版本,我将在下面列出它们,并解释为什么答案都是错误的:

打开websocket连接的安全问题是什么?

Spring websocket与stomp安全-每个用户可以订阅任何其他用户队列?

Websocket:如何将消息推送到目标用户

问题来了:

  • 看看messagingTemplate.convertAndSendToUser -所做的就是添加"用户前缀",然后提供用户名,然后使用不应用安全的messagingTemplate.convertAndSend

  • 然后人们说"你需要像其他地方一样使用spring安全性"-这里的问题是A)我异步地向客户端发送数据,所以B)我将完全在用户的会话之外使用此代码,可能来自不同的用户(例如向另一个登录用户发送通知)。

如果这篇文章与另一篇文章关系太密切,请告诉我,但如果这对我来说是一个大问题,我想公平地对待它。

我可以得到更多的细节,但如果有人需要更多的细节。

新的Spring Security 4x现在完全支持WebSocket,你可以参考预览Spring Security WebSocket支持的链接

或者SpringSecuritySupportWebSocket.html,如果你需要一个完整的例子,

我认为你必须做这些改变:

1)你不能为"/user"启用lesimplebroker,因为它是一个由broker自动处理的特殊队列

2)如果服务器使用例如注释"@SendToUser("/queue/private")",客户端必须订阅队列"/user/queue/private":你不能在队列中添加用户名,因为这是由代理处理的透明操作

我确信这是正确的,因为我在我的设置中使用它。

我没有尝试过convertAndSendToUser()方法,但由于它的语义应该与注释相同,它也应该工作。

您可以在JavaConfig类扩展AbstractSecurityWebSocketMessageBrokerConfigurer中重写configureInbound方法。

@Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
    messages
            .nullDestMatcher().authenticated() 1
            .simpSubscribeDestMatchers("/user/queue/errors").permitAll() 2
            .simpDestMatchers("/app/**").hasRole("USER") 3
            .simpSubscribeDestMatchers("/user/**", "/topic/friends/*").hasRole("USER") 4
            .simpTypeMatchers(MESSAGE, SUBSCRIBE).denyAll() 5
            .anyMessage().denyAll(); 6
    }
}

在这里,您可以配置凭据来订阅通道、发送消息或其他一些事情,如Spring WebSocket文档https://docs.spring.io/spring-security/site/docs/current/reference/html/websocket.html#websocket-authorization

所述。

最新更新