java SpringMVC Websockets 消息传递用户身份验证与 Spring Security
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25004081/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
SpringMVC Websockets Messaging User Authentication with Spring Security
提问by Addo Solutions
I have seen a couple of threads about this issue, but none of them seem to really answer the question directly.
我看过几个关于这个问题的帖子,但似乎没有一个真正直接回答这个问题。
Background, I have spring security installed, working, and running smoothly in other parts of the application. My username is "developer".
背景,我在应用程序的其他部分安装了spring security,工作和运行顺利。我的用户名是“开发者”。
Running on Java 7, Glassfish 4, Spring 4, and using Angular + StompJS
在 Java 7、Glassfish 4、Spring 4 上运行,并使用 Angular + StompJS
Let's get some code here:
让我们在这里得到一些代码:
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);
}
}
Ok, now here is a controller, to send out stuff every 3 seconds:
好的,现在这是一个控制器,每 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());
}
And finally the JavaScript using SockJS
最后是使用 SockJS 的 JavaScript
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;
And finally, for kicks, the pom.xml
最后,为了踢球, 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>
Here is what does work:
这是有效的方法:
- I can produce wonderfully communication back and forth between the client and the server
- It's fast
messagingTemplate.convertAndSend
andmessagingTemplate.convertAndSendToUser
- 我可以在客户端和服务器之间产生奇妙的来回通信
- 它很快
messagingTemplate.convertAndSend
和messagingTemplate.convertAndSendToUser
This is the problem (noted above): Anyone can subscribe to other users feeds.
这就是问题(如上所述):任何人都可以订阅其他用户的订阅源。
Now, there are a few other versions of this floating around, I will list them below, and explain why the answers are all wrong:
现在,还有其他一些版本,我将在下面列出它们,并解释为什么答案都是错误的:
What are the security issues around an open websocket connection?
Spring websocket with stomp security - every user can subscribe to any other users queue?
具有 stomp 安全性的 Spring websocket - 每个用户都可以订阅任何其他用户队列?
Websocket: How To Push A Message To A Target User
Here's the problem:
这是问题所在:
Look at
messagingTemplate.convertAndSendToUser
- All that does is add the "user prefix" and then the username provided and then usemessagingTemplate.convertAndSend
which does not apply security.Then people say that "you need to use spring security just like everywhere else" - the problem here is A) that I am SENDING data to the client asynchronously, so B) I will be using this code completely outside of the user's session, possibly from a different user (say to send a notification to another logged in user).
看看
messagingTemplate.convertAndSendToUser
- 所做的只是添加“用户前缀”,然后添加提供的用户名,然后使用messagingTemplate.convertAndSend
不应用安全性的用户名。然后人们说“您需要像其他任何地方一样使用 spring security”-这里的问题是 A)我正在异步向客户端发送数据,所以 B)我将完全在用户会话之外使用此代码,可能来自不同的用户(比如向另一个登录用户发送通知)。
Let me know if this is too closely related to a different post, but I this is a big problem for me and I wanted to do this justice.
让我知道这是否与不同的帖子过于密切相关,但我这对我来说是一个大问题,我想做到这一点。
I can get more details though if anyone needs more details.
如果有人需要更多详细信息,我可以获得更多详细信息。
采纳答案by phuong
New Spring Security 4x now fully support Web Socket, you can refer the link Preview Spring Security WebSocket Support
新的 Spring Security 4x 现在完全支持 Web Socket,您可以参考链接Preview Spring Security WebSocket Support
Or SpringSecuritySupportWebSocket.htmlin case you need a complete example,
或者SpringSecuritySupportWebSocket.html以防你需要一个完整的例子,
回答by Alessandro Polverini
I think you must make these changes:
我认为你必须做出这些改变:
1) You must not enableSimpleBroker for "/user" because it's a special queue handled automatically by the broker
1) 您不能为“/user”启用SimpleBroker,因为它是由代理自动处理的特殊队列
2) if the server uses for example the annotation "@SendToUser("/queue/private")" the client must subscribe to the queue "/user/queue/private" : you must not prepend the username in the queue because it's a transparent operation handled by the broker
2) 如果服务器使用例如注释 "@SendToUser("/queue/private")" 客户端必须订阅队列 "/user/queue/private" :您不能在队列中添加用户名,因为它是由经纪人处理的透明操作
I'm sure this works correctly because I'm using it in my setup.
我确信这可以正常工作,因为我在我的设置中使用它。
I've not tried with the convertAndSendToUser() method but since its semantic should be the same of the annotation, it should work too.
我没有尝试过 convertAndSendToUser() 方法,但由于它的语义应该与注释相同,它也应该可以工作。
回答by Jhovanni
You can override configureInbound method in a JavaConfig class extending AbstractSecurityWebSocketMessageBrokerConfigurer.
您可以在扩展 AbstractSecurityWebSocketMessageBrokerConfigurer 的 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
}
}
There, you can configure credentials to subscribe a channel, send messages or several other things, as mentioned in Spring WebSocket documntation https://docs.spring.io/spring-security/site/docs/current/reference/html/websocket.html#websocket-authorization
在那里,您可以配置凭据以订阅频道、发送消息或其他一些内容,如 Spring WebSocket 文档https://docs.spring.io/spring-security/site/docs/current/reference/html/websocket 中所述。 html#websocket-授权