我需要使用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。