【发布时间】:2020-10-15 05:14:30
【问题描述】:
我目前正在构建一个受 Spring Security 保护的 Spring Boot Web 应用程序(2.3.1,但在 2.1.7 和 2.1.5 版本中也观察到了以下问题)。我主要使用默认设置(例如嵌入式 Tomcat、嵌入式 H2 数据库、Spring Web-MVC)。我使用以下代码对许可的POST 映射进行了一些自定义身份验证:
UsernamePasswordAuthenticationToken authentication = ...;
SecurityContext context = SecurityContextHolder.getContext();
context.setAuthentication(authentication);
这很好用。由于我想将其用于学生考试,因此我希望将会话与身份验证保持一致,这样以防服务器软件因某种原因崩溃或停机,服务器再次启动时无需重新进行身份验证。
我为此使用了 Spring Session JDBC。我在pom.xml 中添加了以下依赖项:
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-jdbc</artifactId>
</dependency>
下面一行到我的application.properties
spring.session.store-type=jdbc
当我在本地测试时,这一切都很好。我看到会话出现在我的数据库中,一切正常。然而,在实践中,应用程序是从iframe 启动的:学习管理系统执行 LTI 启动,这是一个 POST 请求,其响应以iframe 结束。当我尝试进行测试部署时,我收到了 403 错误,表明我的请求未经过身份验证。经过一天令人沮丧的调试后,我最终将这个问题归结为将spring-session-jdbc 添加到我的项目会导致Web 应用程序在iframe 的每个请求上发送一个新的会话ID cookie。如果我在没有iframe 的情况下重复相同的请求,则相同的应用程序可以正常工作。如果我删除 spring-session-jdbc 依赖项,应用程序在 iframe 内也能正常工作。
如果我在 iframe 中执行身份验证,我会在 Spring Security 调试日志中看到以下内容(exec-1 是成功进行身份验证的地方,exec-2 是 iframe 在被 exec-1 重定向后执行的请求请求):
2020-06-24 22:14:02.015 DEBUG 7474 --- [nio-8031-exec-1] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@671fa7ec
2020-06-24 22:14:02.015 DEBUG 7474 --- [nio-8031-exec-1] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2020-06-24 22:14:02.063 DEBUG 7474 --- [nio-8031-exec-1] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
2020-06-24 22:14:02.113 DEBUG 7474 --- [nio-8031-exec-2] o.s.security.web.FilterChainProxy : /launch/development at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2020-06-24 22:14:02.113 DEBUG 7474 --- [nio-8031-exec-2] o.s.security.web.FilterChainProxy : /launch/development at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2020-06-24 22:14:02.114 DEBUG 7474 --- [nio-8031-exec-2] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
2020-06-24 22:14:02.114 DEBUG 7474 --- [nio-8031-exec-2] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created.
当我在常规浏览器窗口中使用相同的正在运行的应用程序执行相同的请求时,Spring Security 调试日志显示如下:
2020-06-24 22:18:10.518 DEBUG 7474 --- [nio-8031-exec-5] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@671fa7ec
2020-06-24 22:18:10.518 DEBUG 7474 --- [nio-8031-exec-5] w.c.HttpSessionSecurityContextRepository : SecurityContext 'org.springframework.security.core.context.SecurityContextImpl@e1239cdc: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@e1239cdc: Principal: testuserid; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_INSTRUCTOR' stored to HttpSession: 'org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper$HttpSessionWrapper@66670854
2020-06-24 22:18:10.536 DEBUG 7474 --- [nio-8031-exec-5] o.s.s.w.a.ExceptionTranslationFilter : Chain processed normally
2020-06-24 22:18:10.536 DEBUG 7474 --- [nio-8031-exec-5] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
2020-06-24 22:18:10.590 DEBUG 7474 --- [nio-8031-exec-6] o.s.security.web.FilterChainProxy : /home at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2020-06-24 22:18:10.591 DEBUG 7474 --- [nio-8031-exec-6] o.s.security.web.FilterChainProxy : /home at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2020-06-24 22:18:10.592 DEBUG 7474 --- [nio-8031-exec-6] w.c.HttpSessionSecurityContextRepository : Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: 'org.springframework.security.core.context.SecurityContextImpl@82a4fa0f: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@82a4fa0f: Principal: testuserid; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_INSTRUCTOR'
对我来说这似乎很奇怪:如果这纯粹是一个浏览器问题,我是否使用spring-session-jdbc 并不重要。如果spring-session-jdbc 存储我的身份验证的方式有问题,那么它是否发生在iframe 中并不重要。我在这里缺少什么吗?我是不是偶然发现了一个错误?
我可以尝试一种解决方法,在 iframe 中使用一些 javascript,让 POST 在空白选项卡中进行,但这感觉相当难看。
【问题讨论】:
标签: java spring spring-boot spring-security spring-session