如何编写用于连接OAuth 2.0 Secure Spring WebSocket API的JavaScript客户端?

时间:2017-07-26 18:54:01

标签: javascript spring-boot websocket oauth-2.0 spring-websocket

我需要使用spring创建一个Websocket服务器,使用下面的代码

可以轻松完成
 @Configuration
 @EnableWebSocket
 public class WebSocketConfig implements WebSocketConfigurer {
 @Override
 public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
 registry.addHandler(new SocketHandler(), "/poll");
 registry.addHandler(new SocketPushHandler(), "/push");
 }

 }

其中SocketHandler和SocketPushHandler是websocket端点的处理程序类。

直到这件事能够运行服务器并使用普通的socket = new WebSocket(websocketUrl) javascript代码连接到终端。

现在我们需要在API端点上实现OAuth 2.0安全性,这可以通过导入一些Spring安全依赖项轻松完成。\

现在,困难的部分是编写客户端以通过传递Oauth Authorization beaer <token>作为标头的一部分来连接安全端点。 从文档中了解到我们无法将标头发送到Web套接字端点。

因此,根据此Is it possible to secure WebSocket APIs with OAuth 2.0?链接的信息表单,我创建了一个API网关/open-ws Request type GET,客户端将连接到该网关并发送授权标头,此端点在服务器端内部将打开一个WebSocket客户端传递标题的连接javax.websocket.WebSocketContainer支持带有自定义标题的websocket客户端。

所以现在我的javascript首先对Gateway端点进行GET ajax调用,并在成功时发出新的websocket请求。

以下是模仿网关的Spring API

@RequestMapping(value = "/open-ws", method = RequestMethod.GET)
public void getOperatorTokenDefinition(@RequestHeader(value = HttpHeaders.AUTHORIZATION) String bearerToken,
                @RequestHeader(value = "websocketURL") String websocketURL,
                HttpServletRequest acquireTokenServletRequest, HttpServletResponse response) {

    webSocketClient.connecttoserver(websocketURL, acquireTokenServletRequest.getRemoteHost(), bearerToken, response);
    // ResponseEntity<String> responseEntity = new ResponseEntity<>("connected", HttpStatus.OK);
     }

}

以下是我的Spring方客户。

    @Component
public class WebSocketClient {

    private Session client;

public void connecttoserver(String websocketURL,String host,String bearerAccessToken, HttpServletResponse response) {

    final AtomicReference<String> message = new AtomicReference<>();
    Endpoint endpoint = new Endpoint() {
        @Override
        public void onOpen(Session session, EndpointConfig config) {
             System.out.println("WSS OPEN!!!!!");
  try (OutputStream output = response.getOutputStream()) {
            output.write(session.getId());
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


         }
    };

    ClientEndpointConfig.Configurator configurator = new ClientEndpointConfig.Configurator() {

        @Override
        public void beforeRequest(Map<String, List<String>> headers) {

            List<String> connection = new ArrayList<>(1);
            connection.add("Upgrade");
            List<String> origin = new ArrayList<>(1);
            origin.add(originURL);
            List<String> upgradeWebsocket = new ArrayList<>(1);
            upgradeWebsocket.add("WebSocket");
            List<String> host = new ArrayList<>(1);
            host.add(websocketURL);
            List<String> contenttype = new ArrayList<>(1);
            contenttype.add("application/json");
            List<String> authorization = new ArrayList<>(1);
            authorization.add("Bearer " + bearerAccessToken);
            List<String> tenantId = new ArrayList<>(1);
            tenantId.add(tenantID);
            List<String> key = new ArrayList<>(1);
            key.add("HcFOxrSD89ya65X2qMF9lQ==");
            List<String> version = new ArrayList<>(1);
            version.add("13");

            headers.put("Connection", connection);
            headers.put("Upgrade", upgradeWebsocket);
            headers.put("Host", host);
            headers.put("Origin", origin);
            // headers.put("Content-Type", contenttype);
            headers.put("Authorization", authorization);
            headers.put("Sec-WebSocket-Key", key);
            headers.put("Sec-WebSocket-Version", version);
        }

    };


    ClientEndpointConfig clientConfig = ClientEndpointConfig.Builder.create().configurator(configurator).build();

    WebSocketContainer container = ContainerProvider.getWebSocketContainer();
    try {

        // if (!this.client.isOpen())
        this.client = container.connectToServer(endpoint, clientConfig, URI.create(websocketURL));


        client.addMessageHandler(new MessageHandler.Whole<String>() {

            @Override
            public void onMessage(String response) {
                // TODO Auto-generated method stub
                message.set(response);
                // System.out.println("response>>>>>>>>>>>>>>>>>>> "+response.toString());// this dosent work
            }
        });

        System.out.println("Response--------------------------------->" + message.get());
        // client.close();

    } catch (DeploymentException | IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        }

    }
}

以下是JQuery代码

      $(document).ready(function(){
        $("#Websocketconnect").click(function(){
            $.ajax({
                type: 'GET',
                url: hostUrl.value,
                headers: {
                "Authorization":websocketToken.value,
                "websocketURL":websocketUrl.value,
                "Content-type":"text/plain"
                },
                success: function(result){
                $("#readystatus").value = result;
                webSocketCycleEvent(websocketUrl.value);
            }});
        });
    });


    function webSocketCycleEvent(websocketUrl){

      socket = new WebSocket(websocketUrl);
      socket.onerror = function(error) {
        console.log('WebSocket Error: ' + error);
      };


      // Show a connected message when the WebSocket is opened.
      socket.onopen = function(event) {
        socketStatus.innerHTML = 'Connected to: ' + websocketUrl;
        socketStatus.className = 'open';
      };
      socket.onmessage = function(event) {
        var message = event.data;
        messagesList.innerHTML += '<li class="received"><span>Received:</span>' +
                                   message + '</li>';
      };

   socket.onclose = function(event) {
        socketStatus.innerHTML = 'Disconnected from WebSocket.';
        socketStatus.className = 'closed';
      };

      }

      form.onsubmit = function(e) {
          e.preventDefault();

        // Retrieve the message from the textarea.
        var message = messageField.value;
        socket.send(message);
        messagesList.innerHTML += '<li class="sent"><span>Sent:</span>' + message +
                                  '</li>';

        // Clear out the message field.
        messageField.value = '';
        return false;
      };

我不是要连接到websocket并发送socket.id,因为服务器端提供了

javax.websocket.DeploymentException: The HTTP response from the server [400] did not permit the HTTP upgrade to WebSocket
    at org.apache.tomcat.websocket.WsWebSocketContainer.connectToServer(WsWebSocketContainer.java:343)
    at com.example.simplewebsocketserver.WebSocketClient.connecttoserver(WebSocketClient.java:101)
    at com.example.simplewebsocketserver.WebSocketController.getOperatorTokenDefinition(WebSocketController.java:31)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)

所以问题出现了这是连接Oauth 2.0 Websocket的正确方法,如果是,如果没有如何处理上述错误,如果没有如何将标头发送到授权端点。

注意:不使用Stomp,因为我们尚未确认实际的客户端,即UI是否允许/有stomp JS。

0 个答案:

没有答案