Spring Security中SignIn接口无法生成Bearer Token求助
排查SignIn接口无法生成Bearer Token并抛出BadCredentialsException的问题
以下是针对异常触发点JwtTokenValidationFilter的常见排查方向及解决方法:
1. 安全配置错误导致登录接口被JWT过滤器拦截
如果SecurityConfig中误将SignIn接口纳入需要JWT验证的路径范围,登录请求会在生成Token前就被JwtTokenValidationFilter拦截,因无合法Token触发BadCredentialsException。
解决方法:
检查configure(HttpSecurity http)方法,确保登录接口设置为匿名可访问:
@Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .antMatchers("/api/auth/signin").permitAll() // 放行登录接口 .anyRequest().authenticated() .and() .addFilterBefore(new JwtTokenValidationFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class); }
2. JwtTokenValidationFilter未跳过登录请求
如果过滤器逻辑未对登录接口做特殊处理,直接对所有请求执行Token验证,会导致登录请求触发异常。
解决方法:
在过滤器的doFilterInternal方法中添加路径判断,跳过登录接口的验证:
@Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { // 跳过SignIn接口的Token验证 if (request.getRequestURI().contains("/api/auth/signin")) { filterChain.doFilter(request, response); return; } // 原有Token验证逻辑 String token = extractTokenFromRequest(request); if (token != null && jwtValidator.validateToken(token)) { // 解析Token并设置SecurityContext UsernamePasswordAuthenticationToken authToken = createAuthTokenFromToken(token); SecurityContextHolder.getContext().setAuthentication(authToken); } else { throw new BadCredentialsException("Invalid or missing JWT token"); } filterChain.doFilter(request, response); }
3. 用户凭证验证逻辑异常
虽然异常触发在过滤器,但可能是登录流程中用户名/密码验证失败,导致后续流程异常。常见原因包括:
- 用户数据库中凭证被修改
PasswordEncoder实现被变更(比如从BCryptPasswordEncoder改成其他类型)UserDetailsService查询用户逻辑出错
解决方法:
- 检查
UserDetailsService的loadUserByUsername方法,确保能正确查询到用户且密码存储格式匹配:
@Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepo.findByUsername(username) .orElseThrow(() -> new UsernameNotFoundException("User not found: " + username)); // 确保返回的密码与加密器匹配 return new org.springframework.security.core.userdetails.User( user.getUsername(), user.getPassword(), AuthorityUtils.createAuthorityList(user.getRoles().toArray(new String[0])) ); }
- 确认
PasswordEncoderBean未被修改:
@Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); // 保持与注册时一致的加密方式 }
4. JWT生成与验证的密钥/配置不一致
如果JWT签名密钥、过期时间等配置被修改,会导致生成的Token无法通过过滤器验证,或过滤器验证逻辑失效。
解决方法:
检查JwtTokenUtil类,确保生成Token和验证Token使用相同的密钥及算法:
// 固定密钥,避免随意修改 private static final String JWT_SECRET = "your-stable-secret-key-here"; private static final long JWT_EXPIRATION_MS = 1000 * 60 * 60 * 10; // 10小时 public String generateToken(UserDetails userDetails) { return Jwts.builder() .setSubject(userDetails.getUsername()) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + JWT_EXPIRATION_MS)) .signWith(SignatureAlgorithm.HS512, JWT_SECRET) .compact(); } public boolean validateToken(String token) { try { Jwts.parser().setSigningKey(JWT_SECRET).parseClaimsJws(token); return true; } catch (SignatureException | MalformedJwtException | ExpiredJwtException e) { return false; } }
内容的提问来源于stack exchange,提问作者gzhe1056
相关产品推荐
相关产品推荐

