I have a web application built with Kotlin+Spring which identifies users by session ID. On a static front page I have a form which, on submit, sends a POST request to "/start". This is handled by Spring by executing some code and redirecting user to another page "/page" – here’s the minimal code:
@Controller
class SomeController() {
// No GetMapping("/"), because '/' is 100% static
@PostMapping("/start")
fun start(@ModelAttribute someModelAttr: SomeModelAttr, model: Model,
response: HttpServletResponse,
session: HttpSession) {
log.info { "POST /start visited by ${session.id}" }
val id = getSomeStuffSynchronously(someModelAttr, session.id);
response.sendRedirect("page/${id}")
}
@GetMapping("/page/{id}")
fun page(@PathVariable id: String,
model: Model,
session: HttpSession) {
log.info { "GET /page/${id} visited by ${session.id}" }
doOtherStuff(id, session.id);
return "page" // i.e. render a Thymeleaf template
}
The code above assumes that the session ID in start
and page
is the same. However, sometimes (but not always) this is false which breaks stuff for the users. In this situation, the log lines are basically:
POST /start visited by abcd
Log from getSomeStuffSynchronously(someModelAttr, "abcd")
GET /page/123 visited by vxyz
Unfortunately I could not capture headers sent and received by the browser when this happens, because when I tried, I could not reproduce this issue.
I’ve checked:
- This issue might happen regardless of whether the user uses incognito mode in their browser, or not
- I have not yet observed this happening on other requests than front-page->/start->/page/id
- I do not have caching enabled neither at my hosting provider nor in Spring
- I do not have a huge load on my website
- I do not use spring-security
Sessions are Cookie sessions and are managed by spring-session-redis, with timeout in Redis set to 15 minutes. However I did not see any obvious correlation between the time between visits to the site and this issue happening.
My question is: what might cause the session ID to change during the redirect?
2
Answers
Relying on session.id is unreliable between redirects, but as a work-around one can use
RedirectAttributes
and store relevant data that will be needed in the second request handler as flash attributes – see e.g. How to pass the model as a redirect attribute in springThe reason for getting a different sessions, might be because the cookie/url param containing a reference to the session might not have been set/is used (so a new session is generated every time).
It might be an obvious question but are you sure the filter responsible for handling the session is registered? E.g. did you add the
@EnableRedisHttpSession
annotation to a configuration class (see redig http session docs)?