Весенние веб-сокеты без принципала

Я пытаюсь реализовать простое приложение веб-сокетов, которое может отправлять сообщения из одной конечной точки в указанный сеанс, установленный в другом месте. До сих пор мне удавалось использовать аннотацию @SendToUser(), чтобы клиент мог подписаться на канал (как обсуждалось в этом вопросе: Spring Websockets @SendToUser без входа в систему?)

Однако теперь я хочу создать отдельную конечную точку, которая при вызове ищет пользователя, связанного с данными, переданными в эту конечную точку, и отправляет этому пользователю сообщение об этих данных.

Однако я не смог точно определить, как сделать так, чтобы я мог вызывать команду SimpMessagingTemplate convertAndSendToUser(), потому что у моих пользователей нет принципала (я не использую Spring Security).

Мне удалось получить simpSessionId из MessageHeaders, переданных в конечную точку @MessageMapping, но теперь я не могу понять, как использовать simpSessionId для отправки информации из разных частей моего приложения.

Я провел некоторое исследование относительно переопределения метода defineUser() DefaultHandshakeHandler и назначения случайно сгенерированного UUID в качестве имени пользователя пользователю после успешного рукопожатия через веб-сокет (как описано в ответе на этот вопрос: Как ответить неаутентифицированному пользователю в Spring 4 STOMP через конфигурацию WebSocket?), но, поскольку появляющийся принципал имеет значение null, я не совсем уверен, как правильно сгенерировать его и назначить Принципалу для использования с приложением.

В основном мне нужна возможность иметь анонимных пользователей и отправлять им сообщения из разных частей приложения после того, как они создали соединение через веб-сокет.


person Benjamin Wunder    schedule 04.04.2017    source источник


Ответы (1)


Поэтому для всех, кто сталкивается с подобной проблемой, я реализовал свой собственный класс Principal:

package hello;

import java.security.Principal;
import java.util.Objects;

public class AnonymousPrincipal implements Principal {

    private String name;

    @Override
    public String getName() {
        // TODO Auto-generated method stub
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object another) {
        if (!(another instanceof Principal))
            return false;

        Principal principal = (Principal) another;
        return principal.getName() == this.name;

    }

    @Override
    public int hashCode() {
        return Objects.hash(name);
    }
}

Затем я реализовал собственную версию DefaultHandshakeHandler:

package hello;

import java.security.Principal;
import java.util.Map;
import java.util.UUID;

import org.springframework.http.server.ServerHttpRequest;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.DefaultHandshakeHandler;

public class CustomHandshakeHandler extends DefaultHandshakeHandler {

    @Override
    protected Principal determineUser(ServerHttpRequest request,
            WebSocketHandler wsHandler, Map<String, Object> attributes) {
        Principal principal = request.getPrincipal();           

        if (principal == null) {
            principal = new AnonymousPrincipal();

            String uniqueName = UUID.randomUUID().toString();

            ((AnonymousPrincipal) principal).setName(uniqueName);
        }

        return principal;

    }

}

Теперь сеанс веб-сокета получает этот принципал, назначенный ему, когда происходит рукопожатие, поэтому, если пользователь анонимный, ему назначается анонимный принципал, который позволит мне сохранить его имя (сгенерированный UUID) для последующего использования в других частях приложения.

person Benjamin Wunder    schedule 05.04.2017
comment
Как вы использовали UUID в convertAndSendToUser()? Как вы определяете UUID для пользователя, учитывая его имя пользователя? - person Kshitij Bajracharya; 30.03.2019