使用spring security进行授权登录的时候,发现登录接口无法正常捕捉UsernameNotFoundException异常,捕捉到的一直是BadCredentialsException异常。我们的预期是:
- UsernameNotFoundException -> 用户名错误
- BadCredentialsException -> 密码错误
贴几个比较重要的代码:
经过步进法跟踪代码,发现问题所在,位于
AbstractUserDetailsAuthenticationProvider public Authentication authenticate(Authentication authentication)
结论
1、loadUserByUsername方法确实抛出了UsernameNotFoundException
2、走到AbstractUserDetailsAuthenticationProvider的authenticate方法的时候,如果hideUserNotFoundExceptions = true,直接就覆盖了UsernameNotFoundException异常并抛出BadCredentialsException异常,这也就解释了,为什么总是捕捉到BadCredentialsException异常
既然已经找到了是因为hideUserNotFoundExceptions = true导致的问题,那把hideUserNotFoundExceptions = false不就完事了吗?
方案1、修改WebSecurityConfig配置,添加AuthenticationProvider Bean
AbstractUserDetailsAuthenticationProvider public Authentication authenticate(Authentication authentication)
然后配置
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(daoAuthenticationProvider()); }
方案2、在自己的登录验证接口中不用抛出UsernameNotFoundException异常,直接抛出自定义异常,这个异常会被全局异常拦截
@Service public class MyUserDetailService implements UserDetailsService { @Resource private SysUserService sysUserService; @Resource private SysRoleService sysRoleService; @Override public UserDetails loadUserByUsername(String userName){ SysUser sysUser = sysUserService.getByUserName(userName); if (StringUtils.isNull(sysUser)) { throw new CustomException("用户不存在"); } // 查询账号角色 List<String> roleList = sysRoleService.getListByUserId(sysUser.getUserId()); return new UserVo(sysUser,new ArrayList<>()); } }
配置
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(myUserDetailService).passwordEncoder(bCryptPasswordEncoder()); }