security用户名不存在和密码错误等反馈信息是通过捕获异常传递的,所以我们在登录失败处理器中判断一下异常属于哪一个,就可以直到是用户名错了还密码错误了等等情况,再根据需求定制返回信息就行了。
用户名不存在:UsernameNotFoundException;
密码错误:BadCredentialException;
帐户被锁:LockedException;
帐户未启动:DisabledException;
密码过期:CredentialExpiredException;等等!
public AuthenticationFailureHandler failureHandler(){
return new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
httpServletResponse.setCharacterEncoding("utf-8");
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter writer = httpServletResponse.getWriter();
if(e.getClass().equals(UsernameNotFoundException.class)){
//此时异常属于用户名不存在
writer.println(JSONUtil.toJsonStr(JsonResult.failure("用户名不存在!")));
}else {
//此时异常属于密码错误
writer.println(JSONUtil.toJsonStr(JsonResult.failure("密码错误!")));
}
writer.flush();
writer.close();
}
};
}
这里有个小问题security默认的AbstractUserDetailsAuthenticationProvider的authenticate方法,设置了hideUserNotFoundExceptions = true,这里直接就覆盖了UsernameNotFoundException异常并抛出BadCredentialsException异常所以捕获不到UsernameNotFoundException异常,所以我们要重写一下这里
@Bean
public AuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setUserDetailsService(userDetailsService);
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
daoAuthenticationProvider.setHideUserNotFoundExceptions(false);
return daoAuthenticationProvider;
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
//springsecurity通过userDetailsService的loadUserByUsername方法
//去数据库里查询用户并认证
// auth.userDetailsService(userDetailsService)
// //设置密码加密方式,默认为BCryptPasswordEncoder,也是springsecurity默认的密码加密方式
// //这个必须要
// .passwordEncoder(passwordEncoder());
auth.authenticationProvider(daoAuthenticationProvider());
}
还要记得在UserDetailsService里抛出一下异常
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserInfoService userInfoService;
@Override
public UserDetails loadUserByUsername(String userName){
//通过用户名查找用户
UserInfo user = userInfoService.findByUserName(userName);
LoginUser loginUser = new LoginUser();
if (user==null){
//用户为为空直接抛出异常
throw new UsernameNotFoundException("用户名未找到");
}else {
//将查找的用户封装到LoginUser类中
loginUser.setUserInfo(user);
}
return loginUser;
}
}