Как использовать Spring Security с поддержкой Spring Websocket, но без STOMP?

В настоящее время я создаю веб-приложение, которое использует Spring для использования поддержки и безопасности веб-сокетов. Дело в том, что я не хочу использовать STOMP. Он не обновлялся уже около 4-х ваших и мне он не нужен. Итак, я последовал ответу на еще один вопрос в Stackoverflow, чтобы настроить Spring для веб-сокетов с SockJS, но без STOMP.

Теперь я хочу интегрировать Spring Security для аутентификации и авторизации через веб-сокеты. К сожалению, документация привязана к настроить Spring Security для STOMP-веб-сокетов.

Буду очень признателен за любую помощь в настройке Spring Security для моего случая. Может быть, кто-нибудь знает какой-нибудь учебник или пример для этого? Пока не нашел.


person Fencer    schedule 10.04.2018    source источник


Ответы (2)


Сеанс обмена сообщениями Websocket начинается с запроса Http, поэтому можно использовать Spring Security как основу для защиты HTTP-запросов. В весенней безопасности аутентифицированный пользователь и связанный с ним контекст безопасности хранятся в сеансе. Аутентифицированный доступен из рукопожатия Websocket, потому что он передает HTTP-запрос. Spring Websocket определяет HttpSessionHandshakeInterceptor, который можно зарегистрировать в вашей конфигурации с помощью метода addInterceptors.

    @EnableWebSocket
    @Configuration
    public class WebSocketConfig implements WebSocketConfigurer {
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry 
       webSocketHandlerRegistry) {
    webSocketHandlerRegistry.addHandler(createHandler(), 
    "/handler").addInterceptors(new HttpSessionHandshakeInterceptor() 
      {
        @Override
        public void afterHandshake(ServerHttpRequest request, 
         ServerHttpResponse response, WebSocketHandler wsHandler, 
         @Nullable Exception ex) {

            super.afterHandshake(request, response, wsHandler, ex);

        }

        @Override
        public boolean beforeHandshake(ServerHttpRequest request, 
         ServerHttpResponse response, WebSocketHandler wsHandler, 
          Map<String, Object> attributes) throws Exception {
            boolean b = super.beforeHandshake(request, response, 
         wsHandler, attributes) && 
      ((UsernamePasswordAuthenticationToken) 
    request.getPrincipal()).isAuthenticated();
            return b;
        }
         }).withSockJS();
    }

     @Bean
     public WebSocketHandler createHandler() {

    return new MyHandler();

    }
   }

вы также можете проверить аутентифицированное использование в обработчике, который хранится в сеансе веб-сокета

person biiyamn    schedule 10.04.2018
comment
Извините за запоздалую реакцию. Мне пришлось глубже изучить вопрос, чтобы оценить ваш правильный ответ. Я искал чего-то большего, но на самом деле это все, по крайней мере, почти. - person Fencer; 25.04.2018
comment
Поскольку вся удобная конфигурация безопасности, связанная с веб-сокетами, привязана к протоколу сообщений, то есть Stomp, я не могу использовать его, если не использую этот протокол. Однако использование HandshakeInterceptor указывает в правильном направлении. В виде документа заявляет, что его можно использовать для размещения информации в карте атрибутов сеанса веб-сокета, например, всего принципала, хранящегося в запросе. - person Fencer; 25.04.2018
comment
Затем необходимо реализовать детальную авторизацию в соответствии с принципом «сделай сам». Здесь может помочь WebsocketHandlerDecorator. Должен сказать, ваш ответ мог бы быть немного более подробным, но я, конечно, приму его, поскольку он указывает мне правильное направление и, таким образом, очень мне помогает. Спасибо! - person Fencer; 25.04.2018
comment
Спасибо! Мне удалось решить проблему с помощью указания id сеанса. - person mrchebik; 14.04.2019

Я только добавлю ответ выше, указав, как мне удалось его решить.

Моя проблема заключалась в том, что request.getPrinciple() вернул null. Поиграв с просмотров заголовков, я нашел значение cookie. И, подставив то же значение cookie id в запрос веб-сокета, сервер находит principle для этого запроса.

Например, когда мы авторизовались, я делаю запрос к /auth/principal, чтобы получить данные о плеере из базы данных.

@GetMapping(value="/auth/principal")
    public ResponseEntity principal(HttpServletRequest request,
                                    Principal principal) {
        Player player = playerService.findByEmail(principal.getName());

        String jsonString = new JSONObject()
                .put("id", player.getId())
                .put("nickname", player.getNickname())
                .put("cookie", request.getHeader("cookie")).toString();

        return new ResponseEntity(jsonString, HttpStatus.OK);
    }

Затем на стороне клиента, когда я хочу подключиться к websocket, я указываю заголовки запроса, определяя cookie (cookie: COOKIE-ID)

person mrchebik    schedule 13.04.2019