SpringBoot 2.7禁用CSRF后SecurityFilterChain未调用UserDetailsService求助
问题解决:禁用CSRF同时触发HTTP Basic认证的UserDetailsService调用
核心问题分析
你的SecurityConfig里配置了.antMatchers("/**").permitAll(),这意味着所有请求都被允许无需认证,HTTP Basic认证的逻辑根本不会被触发,所以自定义的UserDetailsServiceImpl.loadUserByUsername()自然不会被调用。这和CSRF配置无关,是授权规则的错误导致的。
解决方案
修改SecurityFilterChain的授权规则,把permitAll()改成authenticated(),确保所有请求都需要经过HTTP Basic认证:
@Configuration @EnableWebSecurity public class SecurityConfig { @Autowired private UserDetailsService userDetailsService; @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.authorizeRequests() // 替换permitAll为authenticated,要求所有请求必须认证 .antMatchers("/**").authenticated() .and() // 禁用CSRF,解决POST 401问题 .csrf().disable() // 启用HTTP Basic认证 .httpBasic() .and() // 指定自定义的UserDetailsService .userDetailsService(userDetailsService); return http.build(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }
额外优化建议
UserDetailsServiceImpl的错误修正:
- 不要返回
null,当用户名无效时直接抛出UsernameNotFoundException即可,返回null会导致Spring Security内部报错 - 你当前用
passwordEncoder.encode(username)生成密码,每次编码结果都不同,实际场景中应该从数据库读取已加密的密码,而不是实时编码。测试阶段可以固定一个加密后的密码,比如:// 测试用:假设密码是username对应的明文,提前加密一次 String encryptedPwd = "$2a$10$..."; // 替换为BCrypt加密后的结果 return new User(username, encryptedPwd, true, true, true, true, authList);
- 不要返回
细化授权规则(可选):
如果有不需要认证的路径(比如健康检查接口),可以单独放开:.antMatchers("/actuator/health").permitAll() .anyRequest().authenticated()
内容的提问来源于stack exchange,提问作者cocoz
相关产品推荐
相关产品推荐

