Java SpringMVC WebSocket消息传递用户身份验证与Spring安全性

Java SpringMVC WebSocket消息传递用户身份验证与Spring安全性,java,spring,spring-mvc,spring-security,websocket,Java,Spring,Spring Mvc,Spring Security,Websocket,关于这个问题,我已经看到了一些线索,但似乎没有一条能够直接回答这个问题 在后台,我已经安装了SpringSecurity,并在应用程序的其他部分顺利运行。我的用户名是“开发者” 在Java7、GlassFish4、Spring4上运行,并使用Angular+StompJS 让我们在这里获取一些代码: package com.myapp.config; import org.springframework.context.annotation.Configuration; import org.

关于这个问题,我已经看到了一些线索,但似乎没有一条能够直接回答这个问题

在后台,我已经安装了SpringSecurity,并在应用程序的其他部分顺利运行。我的用户名是“开发者”

在Java7、GlassFish4、Spring4上运行,并使用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());
}
最后,对于kicks,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>

javax.websocket

问题是:

  • 查看
    messagingTemplate.convertAndSendToUser
    ——只需添加“用户前缀”和提供的用户名,然后使用不适用安全性的
    messagingTemplate.convertAndSend

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

让我知道,如果这是一个太密切相关的不同的职位,但我认为这是一个大问题,我想这样做的正义


如果有人需要更多详细信息,我可以获得更多详细信息。

我认为您必须进行以下更改:

1) 不能为“/user”启用SimpleBroker,因为它是由代理自动处理的特殊队列

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

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


我没有尝试convertAndSendToUser()方法,但由于其语义应该与注释相同,因此也应该可以使用。

新的Spring Security 4x现在完全支持Web套接字,您可以参考链接


或者,如果您需要完整的示例,

您可以在扩展AbstractSecurityWebSocketMessageBrokerConfiger的JavaConfig类中重写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文档中所述

响应良好,非常感谢!我现在会继续尝试,并在我知道后尽快更新你/将其标记为解决方案。因此,我尝试完全按照你的建议进行操作,但仍然不起作用。这两种情况之间的关键问题是:您使用的是
@SendToUser
,它已经有了当前的用户会话和范围,很可能还有用户会话。我正在尝试使用
convertAndSendToUser()
向不同的用户发送通知,可能是来自另一个用户,这是我遇到问题的原因。这应该是可以接受的答案。我知道已经很晚了,但是您可以使用clientInboundChannel和clientOutboundChannel来停止不应该传入/传出的订阅和消息。使用内存代理或远程JMS代理可以正常工作吗?嵌入式spring brokerBoy在几个月前会很好!!:)我仍然不认为这能解决@Nitroware的问题,顺便说一句,这也是我的问题。phuong给出的示例向队列中添加了基于角色的权限,但没有阻止角色X中的用户a订阅来自角色X中另一个用户B的消息。我认为这个问题仍然存在。当用户订阅应用程序时,需要的是一个授权挂钩message@nsdiv您可以使用messages.simpSubscribeDestMatchers(“/subscribe”).access(@beanName.check(authentication,message)”)这将使用名为beanName的Springbean并传入当前的身份验证和WebSocket消息。实现check方法以返回true或false。如果您想了解更多详细信息,则需要创建一个新问题,因为注释部分是limitted@RobWinch:创建了一个新问题-@phuong第二个链接已断开这实际上是正确的答案。如果其他用户尝试订阅广播目的地
/topic
/queue
或任何不允许显式的目的地,则此设置就绪后,他们将收到一个错误。
@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

    }
}