Spring Boot中UsernameNotFoundException被转为BadCredentialsException如何解决
问题根因
Spring Security 内置的DaoAuthenticationProvider默认开启了hideUserNotFoundExceptions配置,默认值为true。该设计初衷是避免攻击者通过接口返回差异枚举系统存在的用户名,所以会把所有身份校验阶段抛出的异常(包括你自定义的UsernameNotFoundException)统一包装为BadCredentialsException返回,因此你在失败处理器中拿到的是转换后的异常。
解决方法
你需要自定义DaoAuthenticationProvider实例,关闭异常隐藏配置,再将该实例注册到认证管理器中即可,具体实现如下:
- 声明自定义
DaoAuthenticationProviderBean
@Bean public DaoAuthenticationProvider customDaoAuthenticationProvider(UserDetailsService userDetailsService, PasswordEncoder passwordEncoder) { DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); // 关联你自己实现的用户查询逻辑 provider.setUserDetailsService(userDetailsService); provider.setPasswordEncoder(passwordEncoder); // 关闭用户不存在异常的隐藏配置 provider.setHideUserNotFoundExceptions(false); return provider; }
- 将自定义Provider注册到认证管理器
在你的Spring Security配置类中,将上面声明的Provider加入认证管理器配置:
@Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private DaoAuthenticationProvider customDaoAuthenticationProvider; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(customDaoAuthenticationProvider); } // 其余你的原有Security配置保持不变 }
配置完成后,你在CustomAuthenticationFailureHandler中就能直接获取到原始抛出的UsernameNotFoundException,可以根据异常类型返回对应提示。
注意:关闭异常隐藏后,攻击者可通过接口返回信息判断用户名是否存在,存在用户枚举的安全风险,对外提供服务的场景请谨慎开启该配置。
内容的提问来源于stack exchange,提问作者koa73
相关产品推荐
相关产品推荐

