You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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]))
    );
}
  • 确认PasswordEncoder Bean未被修改:
@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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 21:47:01