java Spring Websockets @SendToUser 无需登录?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25082148/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 07:18:30  来源:igfitidea点击:

Spring Websockets @SendToUser without login?

javaspringspring-securityspring-websocketspring-messaging

提问by kentobi

I have a simple spring application with websocket functionality and everything works so far. Now I want to send a message from my server to a specific client using the @SendToUser annotation. This gives me the error "Ignoring message, no principal info available". I understand that i have no login whatsoever on my server, so every user is "anonymous" and does not have a principal (I am not using spring security for now). But every user has a session-id. Isnt it possible to use the session id somehow to differentiate between users? How can i achieve that so my users get a principal which corresponds to the session-id?

我有一个带有 websocket 功能的简单 spring 应用程序,到目前为止一切正常。现在我想使用 @SendToUser 注释从我的服务器向特定客户端发送一条消息。这给了我错误“忽略消息,没有可用的主要信息”。我知道我的服务器上没有任何登录信息,所以每个用户都是“匿名的”并且没有主体(我现在不使用 spring 安全性)。但是每个用户都有一个会话 ID。是否可以以某种方式使用会话 ID 来区分用户?我怎样才能做到这一点,以便我的用户获得与会话 ID 相对应的主体?

采纳答案by Biju Kunjummen

I think a solution might be to avoid using @SendToUserand use raw SimpMessagingTemplateand to send messages to a destination that you control for open sessions.

我认为一个解决方案可能是避免使用@SendToUser和使用原始数据SimpMessagingTemplate,并将消息发送到您控制的打开会话的目的地。

For eg. assuming that you had some identity for a new websocket session, you can subscribe to a queue with that identifier in the queue name:

例如。假设你有一个新的 websocket 会话的一些身份,你可以订阅一个队列名称中具有该标识符的队列:

stomp.subscribe("/queue/chats" + "-" + mycustomidentifier, onmessage);

Now, on the Spring websocket listener side, you can direct your responses using SimpMessagingTemplate:

现在,在 Spring websocket 侦听器端,您可以使用SimpMessagingTemplate以下命令引导您的响应:

@Controller
public class MyController {


    @Autowired
    private SimpMessagingTemplate simpMessagingTemplate;

    @MessageMapping("/chats")
    public void handleChat(@Payload ChatMessage message) {
        this.simpMessagingTemplate.convertAndSend("/queue/chats-" + "mycustomidentifier", "[" + getTimestamp() + "]:" + message.getMessage());
    }
....

回答by R.S

Use @SendToUserand add "/user/" in front of queue when subscribing (only subscriber side). Rest works magic :-)

@SendToUser订阅时使用并在队列前添加“/user/”(仅限订阅者端)。休息有魔法:-)

Instead of

代替

Java Server: @SendTo("/topic/showResult")

and

JS Client: stompClient.subscribe('/topic/showResult', function(calResult){  ....

use:

利用:

Java Server: @SentToUser("/topic/showResult")

Java Server: @SentToUser("/topic/showResult")

and

JS Client: stompClient.subscribe('/user/topic/showResult', function(calResult){ ....

JS Client: stompClient.subscribe('/user/topic/showResult', function(calResult){ ....

回答by AndrewL

Building on Biju's answerand using the Stomp generated session id(thanks, mariusz2108 in his answer to a similar question), here's what worked for me (based on the canonical example from Spring)

基于Biju 的回答并使用Stomp 生成的会话 ID(感谢mariusz2108 在他对类似问题的回答中),这对我有用(基于Spring 的规范示例

SpringFramework client:

SpringFramework 客户端:

private SimpMessagingTemplate template;

@Autowired
public GreetingController(SimpMessagingTemplate template) {
    this.template = template;
}

@MessageMapping("/hello")
public void greeting(HelloMessage message, @Header("simpSessionId") String sessionId) throws Exception {
    template.convertAndSend("/queue/greeting-"+sessionId, new Greeting("Hello, " + message.getName()));
}

JavaScript client:

JavaScript 客户端:

function connect() {
    var socket = new SockJS('/gs-guide-websocket');
    stompClient = Stomp.over(socket);
    stompClient.connect({}, function (frame) {
        var sessionId = /\/([^\/]+)\/websocket/.exec(socket._transport.url)[1];
        console.log("connected, session id: " + sessionId);
        stompClient.subscribe('/queue/greeting-'+sessionId, function (greeting) {
            showGreeting(JSON.parse(greeting.body).content);
        });
    });
}

Instead of the Stomp session id you could use your web container's Session ID (e.g. JSESSIONID) but now that cookie is not by default accessible from JavaScript(for Tomcat) this is a more difficult prospect.

您可以使用 Web 容器的会话 ID(例如 JSESSIONID)代替 Stomp 会话 ID,但现在默认情况下无法从 JavaScript(对于 Tomcat)访问cookie,这是一个更困难的前景。

回答by airush

Try this. It worked for me

试试这个。它对我有用

@Autowired
private SimpMessagingTemplate messagingTemplate;

@MessageMapping("/getHello")
public void sendReply( MessageHeaders messageHeaders, @Payload String message, @Header(name = "simpSessionId") String sessionId){
        messagingTemplate.convertAndSendToUser(sessionId, "/queue/hello", "Hello "+ message, messageHeaders);
}