Spring Boot集成JWT,Postman请求/authenticate报401 Unauthorized错误
问题描述
在Spring Boot中实现JWT令牌认证,测试/authenticate接口时,向http://localhost:8080/authenticate发送POST请求(请求体为Raw+JSON格式):
{ "username": "admin123", "password": "admin@pass" }
已确认该用户名和密码存在于MySQL数据库中,但请求始终返回401 Unauthorized错误。
相关代码
WebSecurityConfiguration
@Autowired private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; @Autowired private JwtRequestFilter jwtRequestFilter; @Autowired private UserDetailsService jwtService; @Autowired public void setJwtAuthenticationEntryPoint(JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint) { this.jwtAuthenticationEntryPoint = jwtAuthenticationEntryPoint; } @Autowired public void setJwtRequestFilter(JwtRequestFilter jwtRequestFilter) { this.jwtRequestFilter = jwtRequestFilter; } @Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception { return authConfig.getAuthenticationManager(); } @Bean public SecurityFilterChain configure(HttpSecurity httpSecurity) throws Exception { httpSecurity.cors(); httpSecurity.csrf().disable() .authorizeHttpRequests() .requestMatchers("/authenticate").permitAll() .requestMatchers(HttpHeaders.ALLOW).permitAll() .anyRequest().authenticated() .and() .exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint) .and() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class); return httpSecurity.build(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Autowired public void configureGlobal(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception { authenticationManagerBuilder.userDetailsService(jwtService).passwordEncoder(passwordEncoder()); }
JwtRequest
public class JwtRequest { private String username; private String password; public JwtRequest(String username, String password) { this.username = username; this.password = password; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
JwtService
@Service public class JwtService implements UserDetailsService { @Autowired private UserRepository userRepository; @Autowired private JwtUtil jwtUtil; @Autowired private AuthenticationManager authenticationManager; public JwtResponse createJwtToken(JwtRequest jwtRequest) throws Exception { String username = jwtRequest.getUsername(); String password = jwtRequest.getPassword(); authenticate(username, password); final UserDetails userDetails = loadUserByUsername(username); String newGeneratedToken = jwtUtil.generateToken(userDetails); User user = userRepository.findById(username).get(); return new JwtResponse(user, newGeneratedToken); } @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findById(username).get(); if (user != null) { return new org.springframework.security.core.userdetails.User( user.getUserName(), user.getUserPassword(), getAuthorities(user) ); } else { throw new UsernameNotFoundException("Username is not valid"); } } private Set getAuthorities(User user) { Set authorities = new HashSet(); user.getRole().forEach(role -> { authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getRoleName())); }); return authorities; } private void authenticate(String username, String password) throws Exception { try { authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password)); } catch (DisabledException e) { throw new Exception("User is disabled"); } catch (BadCredentialsException e) { throw new Exception("Bad credentials for user"); } } }
JwtController
@RestController @CrossOrigin public class JwtController { @Autowired private JwtService jwtService; @PostMapping({"/authenticate"}) public JwtResponse createJwtToken(@RequestBody JwtRequest jwtRequest) throws Exception { return jwtService.createJwtToken(jwtRequest); } }
排查方向与解决办法
1. 密码编码不匹配(最常见原因)
配置中使用BCryptPasswordEncoder作为密码编码器,必须确保数据库中存储的密码是经过该编码器加密后的字符串。如果创建用户时直接存储明文密码,或者使用了其他加密方式,会导致BadCredentialsException,最终返回401。
解决:创建用户时执行以下逻辑加密密码:
// 注入PasswordEncoder @Autowired private PasswordEncoder passwordEncoder; // 创建用户时加密密码 User user = new User(); user.setUserName("admin123"); user.setUserPassword(passwordEncoder.encode("admin@pass")); // 关键:用编码器加密 userRepository.save(user);
2. User实体字段匹配问题
在JwtService.loadUserByUsername方法中,使用user.getUserName()获取用户名、user.getUserPassword()获取密码,需确认:
- JwtRequest中的
username字段对应User实体的userName属性(数据库字段需一致) - 数据库中存储的用户名确实是
admin123,没有大小写或拼写错误
3. AuthenticationManager配置冲突
Spring Security 5.7+推荐使用SecurityFilterChain替代旧版的configureGlobal配置,两者同时存在可能导致配置不生效。
解决:删除configureGlobal方法,在SecurityFilterChain中直接配置用户详情服务和密码编码器:
@Bean public SecurityFilterChain configure(HttpSecurity httpSecurity) throws Exception { httpSecurity.cors(); httpSecurity.csrf().disable() .authorizeHttpRequests() .requestMatchers("/authenticate").permitAll() .requestMatchers(HttpHeaders.ALLOW).permitAll() .anyRequest().authenticated() .and() .exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint) .and() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 添加以下配置 .userDetailsService(jwtService) .passwordEncoder(passwordEncoder()); httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class); return httpSecurity.build(); }
4. JwtRequestFilter拦截了放行请求
检查JwtRequestFilter.doFilterInternal方法,确保不会拦截/authenticate接口:
@Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { String requestURI = request.getRequestURI(); // 如果是认证接口,直接放行 if ("/authenticate".equals(requestURI)) { chain.doFilter(request, response); return; } // 其他JWT验证逻辑... }
5. 开启调试日志定位问题
添加Spring Security调试日志,查看认证过程的详细错误信息:
在application.properties中添加:
logging.level.org.springframework.security=DEBUG
启动应用后重新测试,查看控制台日志,会输出认证失败的具体原因(如密码不匹配、用户不存在等)。
内容的提问来源于stack exchange,提问作者Georgia

