gpt4 book ai didi

java - Spring boot session management - 为什么有两个sessionRegistry实例?

转载 作者:行者123 更新时间:2023-11-30 10:26:01 33 4
gpt4 key购买 nike

我正在尝试在我的 Spring Boot 应用程序中实现“强制注销”功能(例如,在管理员禁用用户帐户后)。

我按照各种教程中指定的步骤访问 session 注册表,以便使用户的 session 过期(baeldung step 6verbose version on myyurt ;还有 related SO )。

但是,在将 SessionRegistryImpl 注册为 @Bean 之后,在使用调试器时,我看到依赖注入(inject)机制中有 2 个不同的实例:

  • Spring Security 在登录和注销时使用一个 sessionRegistry 实例,并按预期保存主体和 session 。下面的屏幕截图是在登录后截取的 - 我在 registerNewSession() 方法中有一个断点。注意 id 和已经登录用户的 map 。 registerNewSession() happens at login

  • 另一个 sessionRegistry 实例仅提供给我自己的 SessionManager 类,它需要 SessionRegistry 作为依赖项并调用 getAllPrincipals()。请注意 id 不同并且 map 为空(我在多次登录并截取第一个屏幕截图后调用了 getAllPrincipals()) getAllPrincipals() query from my own class

我注册 sessionRegistry bean 的类(我删除了不必要的代码,只留下了我的自定义过滤器,以防它可能与 Springs 自动配置有关):

@EnableWebSecurity
class SecurityConfig extends WebSecurityConfigurerAdapter {

@Bean
public static HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}

@Bean
public static SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}

@Override
protected void configure(HttpSecurity http) throws Exception {

http
.addFilterBefore(myFirstFilter, UsernamePasswordAuthenticationFilter.class)
.addFilterAfter(mySecondFilter, FilterSecurityInterceptor.class)
.formLogin() // skipping details
.and()
.x509() // skipping details
.and()
.logout()
.invalidateHttpSession(true)
.permitAll()
.and()
.authorizeRequests() // skipping details
.and()
.sessionManagement()
.invalidSessionUrl("/login")
.enableSessionUrlRewriting(false)
.maximumSessions(-1)
.maxSessionsPreventsLogin(false)
.sessionRegistry(sessionRegistry())
.expiredUrl("/login?expire");
}
}

我使用 sessionRegistry 依赖项的类:

@Component
class DefaultSessionManager implements SessionManager {
private final SessionRegistry sessionRegistry;

@Autowired public DefaultSessionManager(SessionRegistry sessionRegistry) {
this.sessionRegistry = sessionRegistry;
}

public void expireUserSessions(String username) {
for (Object principal : sessionRegistry.getAllPrincipals()) {
// do stuff, but won't enter because the list is empty
}
}
}

如果有帮助,我使用 Actuator/beans 端点查找 beans 设置,这就是它返回的内容

        {
"bean": "defaultSessionManager",
"aliases":
[
],
"scope": "singleton",
"type": "com.foo.bar.DefaultSessionManager",
"resource": // file path
"dependencies":
[
"sessionRegistry"
]
},

{
"bean": "httpSessionEventPublisher",
"aliases":
[
],
"scope": "singleton",
"type": "org.springframework.security.web.session.HttpSessionEventPublisher",
"resource": "class path resource [com/foo/bar/SecurityConfig.class]",
"dependencies":
[
]
},
{
"bean": "sessionRegistry",
"aliases":
[
],
"scope": "singleton",
"type": "org.springframework.security.core.session.SessionRegistryImpl",
"resource": "class path resource [com/foo/bar/SecurityConfig.class]",
"dependencies":
[
]
},

如果都声明为Singleton,DI系统中怎么会有两个不同的实例呢?您对可能出现的问题有什么建议吗?

我正在使用 spring-boot-starter-parent 1.5.2.RELEASE,它使用 Spring Security 4.2.2.RELEASE。

最佳答案

问题是您的 @Bean 注释方法上的静态关键字。在您调用的配置中

.sessionRegistry(sessionRegistry())

它直接调用静态方法而不是通过 Spring 代理从应用程序上下文中获取 bean。这意味着,对于您的安全配置,您创建一个新实例而不是从应用程序上下文中获取 bean。对于非静态方法,相同调用中的直接方法调用会被 Spring 拦截,然后检查该 bean 是否已存在于应用程序上下文中,如果存在,则返回该 bean。

关于java - Spring boot session management - 为什么有两个sessionRegistry实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45885040/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com