如何为SpringBoot RestController配置认证并解决BadCredentialsException报错
你遇到的BadCredentialsException错误是由setAthenticated方法中的错误认证逻辑导致的,核心问题有两个:
- 调用
authenticationManager.authenticate方法时,传入的凭证是已经经过BCrypt加密的字符串,而AuthenticationManager在校验时会自动将传入的凭证再次用密码编码器加密,和内存中存储的加密密码对比,两次加密后的结果不匹配,直接抛出凭证错误。 - 手动认证逻辑硬编码了固定的admin用户信息,完全没有用到实际登录的用户信息,不符合业务需求。
以下是具体修改方案:
1. 修正手动认证逻辑
既然你已经通过userService.login方法完成了用户名密码的正确性校验,不需要再调用AuthenticationManager重复校验,直接构造已认证状态的Authentication对象存入安全上下文即可,修改后的setAthenticated方法如下:
public void setAthenticated(HttpSession session, User user) { // 三个参数的构造方法会直接标记Authentication为已认证状态 Authentication authentication = new UsernamePasswordAuthenticationToken( user, // 传入实际登录的用户对象作为principal,后续可直接从上下文读取 null, // 已完成认证,不需要再存储密码凭证 user.getAuthorities() ); SecurityContext securityContext = SecurityContextHolder.getContext(); securityContext.setAuthentication(authentication); session.setAttribute("SPRING_SECURITY_CONTEXT", securityContext); }
2. 调整安全规则配置
放开不需要登录即可访问的公开接口,其余接口要求登录认证,移除无用的httpBasic配置,修改configure方法如下:
@Override protected void configure(HttpSecurity http) throws Exception { http.cors().and().csrf().disable() .authorizeRequests() // 公开接口放行 .antMatchers("/user/register", "/user/confirm/**", "/user/login").permitAll() // 其余所有接口需要登录认证 .anyRequest().authenticated(); }
3. 可选优化:规则对齐与冗余清理
如果你不需要内置的admin测试用户,可以删除configureGlobal方法的内存用户配置,避免不必要的资源占用。如果后续需要适配Spring Security的原生权限校验逻辑,注意你的User.getAuthorities方法返回的权限标识需要添加ROLE_前缀,和Spring Security的默认规则对齐:
@Override public Collection<? extends GrantedAuthority> getAuthorities() { final SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority("ROLE_" + role.toString()); return Collections.singletonList(simpleGrantedAuthority); }
完成以上修改后即可正常使用自定义登录接口完成认证,请求受保护接口时Spring Security会自动校验上下文中的登录状态。
内容的提问来源于stack exchange,提问作者Mircea Lutic
相关产品推荐
相关产品推荐

