• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Liutauras Vilda
  • Tim Cooke
  • Jeanne Boyarsky
  • Bear Bibeault
Sheriffs:
  • Knute Snortum
  • paul wheaton
  • Devaka Cooray
Saloon Keepers:
  • Tim Moores
  • Stephan van Hulst
  • Ron McLeod
  • Piet Souris
  • Ganesh Patekar
Bartenders:
  • Tim Holloway
  • Carey Brown
  • salvin francis

Spring Session architecture

 
Greenhorn
Posts: 9
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I'm currently developing an open source webapp with Spring MVC and i am currently a bit helpless in regards to sessions.

My app needs to provide a (big) list of elements to the browser and when that is done, it needs to provide constant real-time updates to inform the browser of changes to the elements in the list. I did that by allowing my Spring sessions to register themselves at some data service to receive all element updates (basically listener pattern). When a session receives an update, it will store it in some buffer list and whenever the client/browser asks for updates, the updates in the buffer will be sent to the browser.

Example session code:


I inject these session into spring singleton controllers, as usual. Problem with that is, that if a user has multiple tabs open, the tabs will steal each others events, because as far as i can see a spring session is not per tab but per user (probably through cookies). Btw, there is an independent mechanism that tells the browser when to ask for updates, that is not the problem (using websocket for that currently).

Controller example:


I currently see only these three solutions:
Possible solutions:
- One session per tab (if that is possible with spring sessions somehow)
- Manage tab session state manually instead of using spring sessions
- Only allow one tab (not preferred)

Have you guys had to deal with stuff like this an maybe can advise me on how to do this properly? Is there some Spring magic that would provide an solution?
 
Bartender
Posts: 20982
128
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Spring is not the problem. For a given instance of a webapp, the same session is shared by all tabs and windows owned by that instance. That is, if you are running both Opera and Firefox, those are 2 separate application instances, and each will have an independent session, but for Firefox (or Opera), all the tabs and windows opened in Firefox (or Opera), the same session will be used.

The problem is in the client, not the server and the server cannot do anything about it.
 
Kath Tharsas
Greenhorn
Posts: 9
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ok thanks so what you are saying is that i should make sure that i have different session cookies for different tabs?

Currently client side sessions seem to work with a cookie called "SESSIONID". I guess the page tells the browser the value for that cookie is or is that done by the browser itself? Haven't really worked with cookies yet apart from what Spring MVC and Spring Security do automatically.
 
Tim Holloway
Bartender
Posts: 20982
128
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
jsessionid is a cookie - or a URL component - that contains the value of a server variable which is a randomly-generated value.

Because HTTP does not run a continuous connection between client and server, but instead connects and disconnects for each HTTP request, the sessionid is the only way that the server can tell one client from another.

However, you cannot just make up your own jsessionid. The jsessionid is synthesized by the server when a session is created. And it can - and does - change values without warning. You cannot cache it or use it for your own purposes. It belongs to the server and all you can do with it as a client is to pass it back in the URL or jsessionid cookie when you make your next request. If you attempt to substitute any other value, the server won't find that sessionid in its session table (it's effectively a hashtable where the sessionid is the key and the HttpSession object is the value).

You cannot create multiple sessions for a single user. If a user has created a session, then any further attempts to createSession simply return the original session. The only way to get a different session is to destroy the first session.

So, in brief, JEE doesn't support what you want and will fight you all the way. And so will your client app, since there's only one copy of each site's cookies per application instance. Individual tabs and windows don't have private cookie collections.
 
Sheriff
Posts: 21783
103
Eclipse IDE Spring VI Editor Chrome Java Ubuntu Windows
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
There are a few ways to solve this, but none uses the HTTP session because of what's already been said.

Two possible solutions:
1) Use server side events (SSE). I haven't gone into the details much, but basically the connection is kept open, the server keeps sending data and the client keeps receiving data. See https://www.baeldung.com/spring-server-sent-events for a small example.

2) Use WebSockets. Unlike HTTP sessions, a WebSocket session is bound to a client page; when the page closes or is redirected to a different URL, the client disconnects and the server session closes. If you have multiple tabs open, then only the session for that tab will be closed. Like with SSE, the server sends data and the client receives it. See https://spring.io/guides/gs/messaging-stomp-websocket/ or https://www.baeldung.com/websockets-spring for more information.

Both require your model to change, from client-pull to server-push.
 
Kath Tharsas
Greenhorn
Posts: 9
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks, you guys helped me a lot.

I am already using websocket, but without STOMP, because it seemed extremly difficult to get a good/deep understanding of the principles behind stomp and all the endpoints rules and how its supposed to be used in a use-cases like mine. I found the Spring documentation for all of this extremely lacking. So currently i use pure, not authenticated websocket to send a "ping" to clients when new updates/events are available on the server, and use normal HTTP to get the updates.

Since my experience with STOMP was so bad, maybe i should look into SSE, since i need spring security authentication to work. Or I put the per-tab state into a hashmap inside the session with a "tab key" for each state that i give out the tabs. Anyway, i think my questions are answered.
 
Rob Spoor
Sheriff
Posts: 21783
103
Eclipse IDE Spring VI Editor Chrome Java Ubuntu Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It's also possible to use WebSockets without STOMP. See https://docs.spring.io/spring/docs/5.1.6.RELEASE/spring-framework-reference/web.html#websocket.
 
Kath Tharsas
Greenhorn
Posts: 9
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Rob Spoor wrote:It's also possible to use WebSockets without STOMP. See https://docs.spring.io/spring/docs/5.1.6.RELEASE/spring-framework-reference/web.html#websocket.



Yeah but (as far as I can see) it does not come with Spring Security integration / authentication so i cannot send data over it. I definitely don't want to write my own authentication code and somehow integrate it into spring security myself.
 
Rob Spoor
Sheriff
Posts: 21783
103
Eclipse IDE Spring VI Editor Chrome Java Ubuntu Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think it does, if you add the HttpSessionHandshakeInterceptor as suggested:

I have used that, and the WebSocketSession objects all have a populated Principal. I don't remember trying to access the endpoint without being logged in, but if the endpoint is properly secured then it should work. I do have the following in my WebSecurityConfigurerAdapter's configure(HttpSecurity http) method:
 
Pay attention! Tiny ad!
Enterprise-grade Excel API for Java
https://products.aspose.com/cells/java
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!