整合BCrypt与Hibernate的Spring Security返回Bad Credentials异常
问题分析与解决
嘿,我一眼就揪出你代码里的问题了!这绝对是导致你一直触发「Bad Credentials」异常的核心原因——你在JWTAuthenticationFilter的attemptAuthentication方法里,把用户名同时当作了密码传入认证请求!
错误代码位置
看这段代码:
@Override public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res) throws AuthenticationException { try { User creds = new ObjectMapper() .readValue(req.getInputStream(), User.class); return authenticationManager.authenticate( new UsernamePasswordAuthenticationToken( creds.getUsername(), creds.getUsername(), // 这里是错误的!应该是creds.getPassword() new ArrayList<>()) ); } catch (IOException e) { throw new RuntimeException(e); } }
你创建UsernamePasswordAuthenticationToken时,第二个参数应该是用户提交的密码,但你却传了两次creds.getUsername()。这就导致Spring Security会拿数据库里的BCrypt加密密码,和你传入的用户名(明文)做比对,结果肯定不匹配,直接触发认证失败。
修复方法
把第二个参数改成creds.getPassword():
return authenticationManager.authenticate( new UsernamePasswordAuthenticationToken( creds.getUsername(), creds.getPassword(), // 修正为获取密码 new ArrayList<>()) );
额外检查点(避免后续踩坑)
修复上面的问题后,建议再确认以下几点:
- 注册时密码必须加密存储:确保你在用户注册接口里,是用
BCryptPasswordEncoder对原始密码加密后再存入数据库的,比如:user.setPassword(bCryptPasswordEncoder.encode(rawPassword)); repository.save(user); - 数据库密码一致性:检查数据库中存储的密码确实是BCrypt加密后的字符串(格式通常是
$2a$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),不是明文。 - 用户名大小写问题:Spring Security默认对用户名的匹配是区分大小写的,如果你需要忽略大小写,可以在
UserDetailsServiceImpl里查询用户名时统一转成小写(比如repository.findByUsername(username.toLowerCase())),同时注册时也要统一处理。
你的完整代码参考(修正后)
修正后的JWTAuthenticationFilter核心部分
@Override public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res) throws AuthenticationException { try { User creds = new ObjectMapper() .readValue(req.getInputStream(), User.class); return authenticationManager.authenticate( new UsernamePasswordAuthenticationToken( creds.getUsername(), creds.getPassword(), new ArrayList<>()) ); } catch (IOException e) { throw new RuntimeException(e); } }
内容的提问来源于stack exchange,提问作者Jmo
相关产品推荐
相关产品推荐

