在将spring会话与Spring Security 集成时,我不确定 SecurityContextImpl#Authentication
应该在spring会话标识会话时填充。
背景:环境 spring-boot
应用程序实际上并不处理登录、注销或创建会话本身。会话是在外部非spring微服务中创建的,并通过mongodb共享。共享和Map会话信息是有效的,并且在Spring Security 之前没有任何问题。
工作原理:
spring会话正确解析会话id
spring会话从会话存储库(mongo)检索会话(使用会话id),并填充属性
请求有一个已填充的会话对象,包括所有属性
什么不起作用:
使用 http.authorizeRequests().antMatchers("admin/**").authenticated()
然后requestion和endpoint(使用会话cookie)绝不会填充 SecurityContext#Authenticated
可能的选择
a) 我明白,我可以实现一个定制 CustomUserNameFromSessionFilter
预先填充 Authenticated
在securecontext中(但authenticated=false),并将其放在securityfilter链的早期。此外,我还实现了一个自定义authenticationprovider CustomFromSessionAuthenticationProvider
,然后它将 Authenticated
基本上 authenticated=true
如果会话有效(此时始终为真)
b) 使用 RememberMeAuthenticationFilter
但是我不确定这个文档如何适合这个目的
c) 利用 AbstractPreAuthenticatedProcessingFilter
但它似乎用于外部身份验证请求
每个选项似乎都不正确,而且这种实现的需求似乎太普遍,以至于没有一个现有的/更好的解决方案。正确的方法是什么?
代码片段
@Override
protected void configure(HttpSecurity http) throws Exception
{
http.csrf().disable();
// Logout is yet handled by PHP Only, we yet cannot delete/write sessions here
http.logout().disable();
http.formLogin().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);
http.authorizeRequests()
.antMatchers("/admin").authenticated();
}
1条答案
按热度按时间ruoxqz4g1#
感谢@steve riesenberg为我提供了足够的提示来找到正确的解决方案!
要了解我的解决方案并了解何时需要执行此额外路线,请首先解释默认集成:
spring security中的经典spring会话集成
当您通过spring boot应用程序使用Spring Security (包括身份验证)时,spring会话和Spring Security 的集成将变得自然,无需任何其他要求。
当您首次通过spring security的身份验证授权(登录)您的用户时,它将:
存储
Authentication
中的对象SecurityContext
该请求的有效性然后SecurityContext
然后将存储在HttpSession
(如果存在的话),在您将spring会话配置为(redis/mongo)的地方使用spring会话。这个
SecurityContext
使用密钥的会话属性存储SPRING_SECURITY_CONTEXT
在公共会话数据中的右侧(序列化)。然后,当您获取此身份验证后提供给您的会话id并发出附加请求时,会发生以下情况
spring会话加载
HttpSession
从您的存储(包括SecurityContext
在会话属性中使用键SPRING_SECURITY_CONTEXT
Spring 保安会打电话来HttpSessionSecurityContextRepository
很早以前SecurityFilter
链和检查HttpSession
是否存在会话属性SPRING_SECURITY_CONTEXT
如果SecurityContext
找到了。如果是,它将使用此选项SecurityContext
并将其作为current
要求SecurityContext
. 因为此上下文包括已通过身份验证的Authentication
对象,该AuthenticationManager/Provider
将跳过身份验证,因为它已全部完成,并且您的请求将被视为已验证。这是一种普通的方式,它有一个要求——身份验证过程(登录)需要编写
SecurityContext
进入HttpSession
对象在登录过程中。我的案例-外部登录过程
在我的例子中,一个外部的、非spring引导的微服务正在处理整个登录过程。尽管如此,它还是将会话存储在(外部)会话存储中,在我的例子中是mongodb。
spring会话已正确配置,可以使用会话cookie/会话id读取此会话,并加载外部创建的会话。
最大的“但是”是,这个外部登录不会存储任何
SecurityContext
在会话数据中,因为它不能这样做。此时,如果您有一个创建会话的外部登录服务,并且它是一个spring引导服务,请确保您编写了SecurityContext
对。因此,所有其他微服务都可以使用会话id和默认的spring会话/安全集成来正确加载该会话(经过身份验证)。由于这不是我的选择,如果您没有选择,以下解决方案似乎是spring boot/security imho中的“按设计”方式:
你实现你自己的
CustomHttpSessionSecurityContextRepository
并通过将其注册到安全配置中这可以确保我们更换库存
HttpSessionSecurityContextRepository
通过我们自己的实现。现在,我们的自定义实现
所以现在改变了spring security加载
SecurityContext
会议结束后。而不是期待SecurityContext
为了已经存在,我们检查会话是否正确,并创建SecurityContext
从给定的数据存储并返回它。这将使整个下面的链使用并尊重这一点SecurityContext