4

I'm experimenting with Spring 4 WebSocket STOMP application. Is there a way to reply to a single unauthenticated user on condition that each user has unique session ID? Right now I can only either broadcast a message or send it directly to an authenticated user.

@Controller
public class ProductController {

    @MessageMapping("/products/{id}")
    @SendTo("/topic") // This line makes return value to be broadcasted to every connected user.
    public String getProduct(@DestinationVariable int id) {
        return "Product " + id;
    }
}
Anton Moiseev
  • 2,834
  • 4
  • 24
  • 30
  • check my answer from http://stackoverflow.com/questions/25082148/spring-websockets-sendtouser-without-login/26242797#26242797 – R.A Mar 21 '15 at 13:14
  • Or my alternate answer to the same question [ _Spring Websockets @SendToUser without login?_](http://stackoverflow.com/a/43430736/1847378) – AndrewL Apr 15 '17 at 20:11

2 Answers2

8

You can assign an anonymous identity to incoming users. There are two ways to do it.

One, you can configure a sub-class of DefaultHandshakeHandler that overrides determineUser and assigns some kind of identity to every WebSocketSession. This requires 4.0.1 by the way (currently build snapshots are available) that will be released on Monday Jan 23, 2014.

Two, the WebSocket session will fall back on the value returned from HttpServletRequest.getUserPrincipal on the handshake HTTP request. You could have a servlet Filter wrap the HttpServletRequest and decide what to return from that method. Or if you're using Spring Security which has the AnonymousAuthenticationFilter, override its createAuthentication method.

Rossen Stoyanchev
  • 4,910
  • 23
  • 26
  • Thank you for your reply! Will be able to try it only tomorrow. – Anton Moiseev Jan 23 '14 at 21:06
  • 2
    Thanks, the first option worked out. One question. When I do `@SendToUser("/prodcuts")` it always appends unique user identifier to the path: `/user/products-user0`, `/user/products-user1` and so on. Though I use UUID as the name when I create Principal for anonymous user. Is there a way to override this behaviour? Is it really safe to allow web server just incrementing this ID? – Anton Moiseev Jan 24 '14 at 15:28
0

@SendToUser("/products") should result in a message to destination "/user/{username}/products". That message will be handled by the UserDestinationMessageHandler, which transforms the destination to "/products-user{sessionId}" and re-sends the message.

So I'm not quite sure what "/user/products-user0" is. It surprises me in two ways. First if it starts with "/user" then that's the destination before the transformation and should be followed by the user name (i.e. "/user/{username}/products").

The fact that it ends with "-user0" makes it look like the destination after the transformation but then it shouldn't start with "/user". In any case the 0, 1 in that case would be the WebSocket session id. What server is this?

Rossen Stoyanchev
  • 4,910
  • 23
  • 26
  • 1. Confirm `@SendToUser` transforms destination to `/user/{username}/products` where `{username}` is UUID I explicitly assign as the name for every anonymous user's principal. 2. Indeed, there is no `/user/` prefix in the `destination` header _on the client side_, sorry, my bad. 3. Regarding `-user0` suffix, I was expecting to see user's UUID instead of 0, but now I see it reflects WebSocket's session, not user ID. I use Tomcat v7.0.47 embedded by default with Spring Boot 1.0.0.RC1. Is this behavior server-specific? Don't you know if I can override this session ID behavior? – Anton Moiseev Jan 26 '14 at 20:20
  • 1
    Yes it is server specific. You can ask on the Tomcat user list for suggestions on how to customize it, or if it is possible. Also when using SockJS (with the WebSocket transport) the session id is the SockJS session id. – Rossen Stoyanchev Jan 28 '14 at 17:34