我有一个 HTML 表单,可以向 Spring Boot 后端发出 REST API 调用。我正在使用 Spring Session 来处理同一用户的并发登录。如果我在下面的代码中使用expiredUrl,当当前会话过期时,我会被重定向到login.html页面。当我单击请求 HTML 页面的菜单项时,效果很好。
如果我已经在某个页面上,并且单击向服务器发出 AJAX 调用的按钮,则当会话过期时,我会收到 302(获取/重定向)状态,然后是带有 200 状态的 login.html 页面。因此 Ajax 调用得到的响应为 200,这是不正确的。 我在下面的代码中将expiredUrl替换为expiredSessionStrategy,但是expiredSessionStrategy根本没有被调用。 如果你们中有人知道原因或发现我的代码中存在缺陷,请告诉我。我在 Spring 会话文档中搜索了 expiredSessionStrategy,但没有找到任何内容。
我在 stackoverflow 上发现了几篇文章,建议使用 AjaxAwareAuthenticationEntryPoint 在会话到期时获取 Ajax 调用的自定义响应。我会尝试这种方法,但我想知道为什么在我的情况下没有调用expiredSessionStrategy。
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(..)
.authorizeHttpRequests(..)
.oauth2Login(oauth2 -> {
oauth2
.userInfoEndpoint(userInfo -> userInfo
.oidcUserService(this.oidcUserService())
)
.loginPage("/login.html")
.failureUrl("/loginFailure")
.successHandler(customOauth2SuccessHandler) ;
}
)
.logout(...)
.sessionManagement((sessions) -> sessions
.maximumSessions(1)
.sessionRegistry(this.sessionRegistry())
.expiredSessionStrategy( event ->
{
String URI = event.getRequest().getRequestURI();
System.out.println("URI="+URI);
if (URI.endsWith(".html"))
event.getResponse().sendRedirect("/login.html?msgCode=4");
else
{
event.getResponse().setContentType("application/json");
event.getResponse().sendError(440, "Session has expired. Please login again !");
}
}
)
//.expiredUrl("/login.html?msgCode=4")
);
return http.build();
}
我打开了 Spring Security 包的跟踪,这就是我发现的。当会话过期时,Spring会话管理正在删除过期的会话。您可能可以设置一些属性来控制此行为,但我还没有研究过。当我的应用程序发出 Ajax API 请求时,过期的会话 cookie 会与请求一起发送到服务器。由于该会话已被 Spring 删除,因此它被视为无效会话,而不是过期会话。所以我使用 invalidSessionStrategy 而不是 expiredSessionStrategy 并且事情对我有用。我创建了 InvalidSessionStrategy 接口的新实现,并使其发送 Ajax API 请求的 JSON 响应。
我这边的一个错误是我认为expiredURL 正在工作,因此我对expiredSessionStrategy 没有被调用感到困惑。实际上,expiredURL 从未被调用。默认行为是当 Spring 检测到无效会话时重定向到登录页面。由于在我的情况下,expiredURL 也重定向到登录页面,我认为expiredURL 正在工作,这又是我这边的一个错误,如果这误导了你们中的任何人,我真的很抱歉。