如何正确禁用Spring Security中的自动密码生成功能?
我用自定义过滤器搭建了Spring Security环境,没用到UserDetailsService组件,所以没创建这个类。认证功能正常运行,但日志里仍会出现自动生成的密码。我通过声明一个空的InMemoryUserDetailsManager解决了此问题,但存在以下疑惑:
- Spring Security是否仍会尝试从请求中获取用户名并通过UserDetailsService进行认证?
- 默认密码是由默认UserDetailsService生成但未被实际使用吗?
- 是否存在禁用该功能的正确方式?
- 能否不声明自定义UserDetailsService就取消自动密码生成?
我的配置代码如下:
@Configuration @EnableWebSecurity @RequiredArgsConstructor public class SecurityConfig { private final JwtAuthenticationFilter jwtAuthenticationFilter; private final JwtAuthenticationEntryPoint unauthorizedHandler; @Bean public InMemoryUserDetailsManager userDetailsService(PasswordEncoder passwordEncoder) { // We overwrite the default user detail service so it does not generate default user and password return new InMemoryUserDetailsManager(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(10); } @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.csrf(AbstractHttpConfigurer::disable); http.cors(AbstractHttpConfigurer::disable); http.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); http.exceptionHandling(exception -> exception .authenticationEntryPoint(unauthorizedHandler)); http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); http.authorizeHttpRequests(authorize -> authorize .requestMatchers(HttpMethod.OPTIONS).permitAll() .requestMatchers("/api/auth/**").permitAll() .requestMatchers("/error").permitAll() .requestMatchers("/api/public/**").permitAll() .anyRequest().authenticated()); return http.build(); } }
解答
1. Spring Security是否仍会尝试通过UserDetailsService认证?
不会。你已经将自定义的JwtAuthenticationFilter添加到UsernamePasswordAuthenticationFilter之前,并且配置了SessionCreationPolicy.STATELESS。默认的用户名密码认证流程由UsernamePasswordAuthenticationFilter触发,而你的JWT过滤器会优先处理请求,完成认证后直接设置SecurityContext,后续默认过滤器不会再触发基于UserDetailsService的认证逻辑。
2. 默认密码是生成了但未被使用吗?
是的。当Spring Security检测到没有自定义的UserDetailsService或UserDetails Bean时,会自动配置一个默认的InMemoryUserDetailsManager,其中包含一个默认用户(用户名user,密码随机生成并打印到日志)。但在你的场景中,这个默认用户完全不会被用到——因为你的认证完全依赖JWT过滤器,根本不会走默认的用户名密码校验流程。
3. 禁用默认用户生成的正确方式
有两种更优雅的方案,无需声明空的InMemoryUserDetailsManager:
方案一:通过配置关闭自动用户生成
在application.properties或application.yml中添加以下配置:spring.security.user.enabled=false该配置会直接禁用Spring Security自动创建默认用户的逻辑,从根源上解决日志打印默认密码的问题。
方案二:移除默认认证过滤器
若不想修改配置,也可以在SecurityFilterChain中直接移除UsernamePasswordAuthenticationFilter,不过这种方式不如配置简洁:http.removeFilter(UsernamePasswordAuthenticationFilter.class);更推荐使用第一种配置方式,直观且易于维护。
4. 能否不声明自定义UserDetailsService就取消自动密码生成?
完全可以。使用上述方案一的spring.security.user.enabled=false配置即可,无需声明任何自定义的UserDetailsService Bean,就能让Spring Security跳过默认用户的自动配置。
内容的提问来源于stack exchange,提问作者maybesomename

