In the servlet world there would be things like cookies and HttpSession for me to identify who was hitting my restful service to route the request to the correct data. Is it a good idea to use the Sec-WebSocket-Key as though it is a cookie identifying the client connection?
Specifically I am using the socko scala library (an akka webserver based on netty) to implement a websocket server starting from the demo app at socko-examples. Socko is wrapping a netty Channel and passing a netty WebSocketFrame into the application code. I would then like to dispatch the frame of incoming data based on "some identity" for the client connection which I have previously associated to the end users data (e.g their shopping basket). To do this I have written extension methods to expose the Sec-WebSocket-Key http header as though it is a top level property of the objects which come into the application by digging out the http header from the original websocket handshake:
package org.mashupbots.socko.examples.websocket
// pimp my library pattern to add extension method
object ChatWebSocketExtensions {
import org.mashupbots.socko.events.WebSocketFrameEvent
class WebSocketFrameEventWithSecWebSocketKey(wsFrame: WebSocketFrameEvent) {
def secWebSocketKey: String = {
wsFrame.initialHttpRequest.headers.get("Sec-WebSocket-Key").getOrElse("null")
}
}
implicit def webSocketFrameEventWithSecWebSocketKey(wsFrame: WebSocketFrameEvent) = new WebSocketFrameEventWithSecWebSocketKey(wsFrame)
import org.mashupbots.socko.events.WebSocketHandshakeEvent;
class WebSocketHandshakeEventWithSecWebSocketKey(event: WebSocketHandshakeEvent) {
def secWebSocketKey: String = {
val option = Option(event.nettyHttpRequest.getHeader("Sec-WebSocket-Key"))
return option.getOrElse("null");
}
}
implicit def webSocketHandshakeEventWithSecWebSocketKey(event: WebSocketHandshakeEvent) = new WebSocketHandshakeEventWithSecWebSocketKey(event)
}
Thats only some syntactic sugar so that the app code does not have to go digging around in the low level objects to get the Sec-WebSocket-Key header and just access it as though it were a first class property:
val routes = Routes({
case WebSocketHandshake(wsHandshake) => wsHandshake match {
case GET(PathSegments("websocket" :: roomNumber :: Nil)) => {
log.info("Handsake to join room " + roomNumber)
wsHandshake.authorize(onComplete = Some((event: WebSocketHandshakeEvent) => {
val identity = event.secWebSocketKey;
log.info("Authorised connection:" + identity);
// do something with this identified user connection
}))
}
}
case WebSocketFrame(wsFrame) => {
// Once handshaking has taken place, we can now process frames sent from the client
val identity = wsFrame.secWebSocketKey;
log.info("chat from:" + identity);
// do something with this identified data frame
}
})
My question is whether this is good practice or is there a better way to identify the user connection?
'Sec-WebSocket-Key' identifies a connection.
However, I'm not too sure if using 'Sec-WebSocket-Key' is a good ideas to identify a "session".
This is because 'Sec-WebSocket-Key' does not accommodate scenario where the connection is dropped and the client is required to establish a new connection. A new 'Sec-WebSocket-Key' may be issued. The user would loose his/her session.
With HTTP, a session is typically associated with a cookie or an id in the URL - both of which are independent of the HTTP connection. In this way, multiple HTTP connections may be used for a single user session.
I would suggest you use something similar for your web socket "session".
As part of your hand-shake and successful login, get the server to send the client a session id. The client should send the session id back to the server with each request.
In this way, you can use javascript like https://github.com/joewalnes/reconnecting-websocket to provide network resiliency in your application code.
Hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With