什么可能导致 session ID 在重定向后有时会发生变化(Java/Kotlin Spring 网络应用程序)?
What might cause a session ID to sometimes change after redirect (Java/Kotlin Spring web app)?
我有一个使用 Kotlin+Spring 构建的 Web 应用程序,它通过 session ID 识别用户。在静态首页上,我有一个表单,在提交时向“/start”发送一个 POST 请求。这是由 Spring 通过执行一些代码并将用户重定向到另一个页面“/page”来处理的——这是最少的代码:
@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
}
上面的代码假设start
和page
中的session ID是一样的。然而,有时(但不总是)这是错误的,这会破坏用户的东西。在这种情况下,日志行基本上是:
POST /start visited by abcd
Log from getSomeStuffSynchronously(someModelAttr, "abcd")
GET /page/123 visited by vxyz
不幸的是,发生这种情况时,我无法捕获浏览器发送和接收的 headers,因为当我尝试时,我无法重现此问题。
我检查过:
- 无论用户是否在其浏览器中使用隐身模式,此问题都可能发生
- 除 front-page->/start->/page/id
之外,我还没有观察到这种情况发生在其他请求上
- 我的托管服务提供商和 Spring
都没有启用缓存
- 我的网站负载不大
- 我不使用spring-security
会话是 Cookie session,由 spring-session-redis 管理,Redis 中的超时设置为 15 分钟。但是,我没有发现访问该站点的时间与此问题发生之间有任何明显的相关性。
我的问题是:什么可能导致 session ID 在重定向期间发生变化??
依赖 session.id 在重定向之间是不可靠的,但作为一种变通方法,可以使用 RedirectAttributes
并将第二个请求处理程序中需要的相关数据存储为 flash 属性——参见例如
获得不同会话的原因可能是因为 cookie/url 包含对会话的引用的参数可能未被 set/is 使用(因此每次都会生成一个新会话)。
这可能是一个显而易见的问题,但您确定负责处理会话的过滤器已注册吗?例如。您是否将 @EnableRedisHttpSession
注释添加到配置 class(参见 redig http session docs)?
我有一个使用 Kotlin+Spring 构建的 Web 应用程序,它通过 session ID 识别用户。在静态首页上,我有一个表单,在提交时向“/start”发送一个 POST 请求。这是由 Spring 通过执行一些代码并将用户重定向到另一个页面“/page”来处理的——这是最少的代码:
@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
}
上面的代码假设start
和page
中的session ID是一样的。然而,有时(但不总是)这是错误的,这会破坏用户的东西。在这种情况下,日志行基本上是:
POST /start visited by abcd
Log from getSomeStuffSynchronously(someModelAttr, "abcd")
GET /page/123 visited by vxyz
不幸的是,发生这种情况时,我无法捕获浏览器发送和接收的 headers,因为当我尝试时,我无法重现此问题。 我检查过:
- 无论用户是否在其浏览器中使用隐身模式,此问题都可能发生
- 除 front-page->/start->/page/id 之外,我还没有观察到这种情况发生在其他请求上
- 我的托管服务提供商和 Spring 都没有启用缓存
- 我的网站负载不大
- 我不使用spring-security
会话是 Cookie session,由 spring-session-redis 管理,Redis 中的超时设置为 15 分钟。但是,我没有发现访问该站点的时间与此问题发生之间有任何明显的相关性。
我的问题是:什么可能导致 session ID 在重定向期间发生变化??
依赖 session.id 在重定向之间是不可靠的,但作为一种变通方法,可以使用 RedirectAttributes
并将第二个请求处理程序中需要的相关数据存储为 flash 属性——参见例如
获得不同会话的原因可能是因为 cookie/url 包含对会话的引用的参数可能未被 set/is 使用(因此每次都会生成一个新会话)。
这可能是一个显而易见的问题,但您确定负责处理会话的过滤器已注册吗?例如。您是否将 @EnableRedisHttpSession
注释添加到配置 class(参见 redig http session docs)?