Spring Security HTTP Basic认证如何强制每次请求重新校验?
解决Spring Security HTTP Basic认证每次请求重新校验的问题
问题原因
Spring Security默认会把认证成功的Authentication对象存入会话(Session)的SecurityContext中,后续请求会直接复用这个已认证对象,不会重新校验请求头里的用户名密码,这就是日志里出现“Did not re-authenticate”的原因。
解决方案
1. 禁用会话持久化,强制每次请求重新认证
在SecurityFilterChain配置中添加会话管理策略,设置为STATELESS(无状态),让Spring Security不在会话中保存认证状态,每次请求都必须重新校验凭证:
@Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { log.info("In securityFilterChain with HttpSecurity"); http .csrf().disable() .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // 关键配置 .authorizeRequests() .anyRequest().authenticated() .and() .httpBasic() .authenticationEntryPoint(authEntryPoint); return http.build(); }
2. 确保用户信息能实时更新
你当前使用InMemoryUserDetailsManager存储用户,要动态修改密码的话,必须更新内存中的用户对象,而不是每次创建新的InMemoryUserDetailsManager实例。可以把它单独注册为Bean,修改密码时调用其updateUser方法:
@Bean public InMemoryUserDetailsManager userDetailsService() { UserDetails user = User.builder() .username("basic") .password(encoder.encode("basic123")) .roles("USER") .build(); return new InMemoryUserDetailsManager(user); } // 修改密码时调用此方法更新用户信息 public void updateUserPassword(String username, String newPassword) { UserDetails existingUser = userDetailsService().loadUserByUsername(username); UserDetails updatedUser = User.builder() .username(existingUser.getUsername()) .password(encoder.encode(newPassword)) .roles(existingUser.getAuthorities().stream() .map(GrantedAuthority::getAuthority) .map(role -> role.replace("ROLE_", "")) .toArray(String[]::new)) .build(); userDetailsService().updateUser(updatedUser); }
3. 修正AuthenticationManager配置
你当前的AuthenticationManagerBean重复构建了UserDetailsService,会导致和业务中使用的实例不一致,修改后的用户信息无法生效。调整为注入已有的UserDetailsService:
@Bean public AuthenticationManager authenticationManager(HttpSecurity http, UserDetailsService userDetailsService) throws Exception { return http.getSharedObject(AuthenticationManagerBuilder.class) .userDetailsService(userDetailsService) .and() .build(); }
完成以上配置后,每次请求都会重新解析HTTP Basic头的用户名密码,调用UserDetailsService获取最新用户信息校验,使用旧密码时会返回401 Unauthorized。
内容的提问来源于stack exchange,提问作者kakoli
相关产品推荐
相关产品推荐

