这是Sping Boot 版本3.0.1的问题。这在版本2.7.5中运行得非常好。
我的应用程序使用Spring Security和JDBC会话。因此,我将X-Auth-Token
保存在数据库(PostgreSQL)的spring_session
表中。我实现了UserDetailsService
接口,以便在调用登录控制器方法时从数据库中获取用户。
当迁移到新的Sping Boot 3版本时,主要的变化发生在WebSecurityConfig
类中。以前它是从WebSecurityConfigurerAdapter
类扩展而来的。所以我知道问题出在这个类的某个地方。
下面我将复制并粘贴WebSecurityConfig
类的旧版本2.7.5(运行良好)和新版本3.0.1:
Spring Boot 版本2.7.5
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
@Autowired
UserDetailsService userDetailsService;
@Autowired
private AuthenticationFailureHandler authenticationFailureHandler;
@Autowired
private PasswordEncoder passwordEncoder;
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.cors()
.and()
.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/api/usermanager/auth/login").permitAll()
.antMatchers(HttpMethod.GET, "/api/usermanager/image/org/**").permitAll()
.antMatchers("/invalidSession*").anonymous()
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll()
.failureHandler(authenticationFailureHandler)
.and()
.sessionManagement()
.sessionFixation()
.migrateSession()
.maximumSessions(1)
.expiredUrl("/sessionExpired.html")
.maxSessionsPreventsLogin(false);
}
@Override
public void configure(WebSecurity web) {
web
.ignoring()
.antMatchers("/docs/**", "/resources/**", "/static/**");
}
@Bean
public AuthenticationFailureHandler myFailureHandler() {
return new CustomAuthenticationFailureHandler();
}
@Bean
public HttpSessionIdResolver httpSessionStrategy() {
return HeaderHttpSessionIdResolver.xAuthToken();
}
@Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("client")
.password(passwordEncoder.encode("Client@Venturi"))
.roles("USER");
var daoAC = new DaoAuthenticationConfigurer(userDetailsService);
daoAC.passwordEncoder(passwordEncoder);
auth.apply(daoAC);
}
}
Spring Boot 版本3.0.1
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class WebSecurityConfig {
@Autowired
private UserDetailsService userDetailsService;
@Bean
public AuthenticationManager authenticationManager(HttpSecurity http,
PasswordEncoder passwordEncoder)
throws Exception {
var daoAC = new DaoAuthenticationConfigurer(userDetailsService);
daoAC.passwordEncoder(passwordEncoder);
var builder = http.getSharedObject(AuthenticationManagerBuilder.class);
builder.apply(daoAC);
return builder.build();
}
private static final String[] AUTH_WHITELIST = {
"/api/usermanager/auth/login"
};
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.exceptionHandling()
.and()
.cors()
.and()
.httpBasic()
.and()
.authorizeHttpRequests(
requests -> requests.
requestMatchers(AUTH_WHITELIST).permitAll()
.anyRequest().authenticated()
)
.sessionManagement()
.sessionFixation()
.migrateSession()
.maximumSessions(1)
.expiredUrl("/sessionExpired.html")
.maxSessionsPreventsLogin(false);
return http.build();
}
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring().requestMatchers(HttpMethod.GET,
"/docs/**", "/resources/**", "/static/**"
);
}
@Bean
public AuthenticationFailureHandler myFailureHandler() {
return new CustomAuthenticationFailureHandler();
}
@Bean
public HttpSessionIdResolver httpSessionStrategy() {
return HeaderHttpSessionIdResolver.xAuthToken();
}
@Bean
public HttpSessionIdResolver httpSessionIdResolver() {
return HeaderHttpSessionIdResolver.xAuthToken();
}
@Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}
}
当我调用上面的auth/login控制器API时,我得到了填充在spring_session
表中的会话ID,但是该表中的principal_name
是null
,我希望您知道spring_session
表是Spring Session创建的用于保存会话信息的默认表。
在2.7.5版本中,principal_name
将被保存(用户登录名)。因此,在后续请求中,我可以通过在HTTP请求头中传递x-auth-token
来获取用户。因此,现在我的问题是,当我调用上述控制器API时,principal_name
始终是spring_session
表中的null
。
在将WebSecurityConfig
类转换为Sping Boot 版本3时,有人能看到我是否做错了什么吗?
1条答案
按热度按时间u91tlkcl1#
与以前版本的差异是由于以下更改:https://github.com/spring-projects/spring-security/issues/11110
您可以使用自动保存SecurityContextHolder设置的旧策略(已弃用):