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

自定义Spring Security认证管理器未抛出空凭证异常问题

空凭证未触发BadCredentialsException的原因及解决方法

核心原因

你的代码仅校验了凭证是否为null,但未处理空字符串场景:

  • 当前端传入空字符串(如{"username":"", "password":""})时,LoginDTO的username和password会被反序列化为空字符串(而非null),导致AuthManager中的null判断条件不触发。
  • 空字符串会进入后续loadUser流程,如果detailsService.loadUserByUsername对空字符串返回了合法的UserDetails对象(比如默认用户),认证会直接“成功”,不会抛出异常;若该方法抛出异常,也可能被Spring Security全局异常处理机制捕获,导致控制台无输出。

验证方式

在AuthManager的authenticate方法中添加日志,打印凭证实际值:

logger.info("principal value: '{}', credentials value: '{}'", 
    authentication.getPrincipal(), authentication.getCredentials());

如果输出为principal value: '', credentials value: '',即可确认是空字符串导致的问题。

解决方案

1. 修改AuthManager校验逻辑

同时校验null和空字符串(含全空格情况):

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    String principal = authentication.getPrincipal() != null ? authentication.getPrincipal().toString().trim() : null;
    String credentials = authentication.getCredentials() != null ? authentication.getCredentials().toString().trim() : null;
    
    if (principal == null || principal.isEmpty() || credentials == null || credentials.isEmpty()) {
        throw new BadCredentialsException("Credentials are wrong");
    }
    
    UserDetails user = loadUser(authentication);
    return new UsernamePasswordAuthenticationToken(user.getUsername(), null, user.getAuthorities());
}

2. 提前在请求参数层面校验

在LoginDTO中添加参数校验注解,提前拦截空凭证请求:

import jakarta.validation.constraints.NotBlank;

public class LoginDTO {
    @NotBlank(message = "Username cannot be empty or whitespace")
    private String username;

    @NotBlank(message = "Password cannot be empty or whitespace")
    private String password;

    // getter and setter
}

并在UsernamePasswordJsonFilter中触发校验:

@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
    try {
        LoginDTO authenticationRequest = objectMapper.readValue(request.getInputStream(), LoginDTO.class);
        
        // 手动触发参数校验
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        Validator validator = factory.getValidator();
        Set<ConstraintViolation<LoginDTO>> violations = validator.validate(authenticationRequest);
        if (!violations.isEmpty()) {
            throw new BadCredentialsException(violations.iterator().next().getMessage());
        }
        
        Authentication auth = new UsernamePasswordAuthenticationToken(authenticationRequest.getUsername(),
                authenticationRequest.getPassword());
        logger.info("UsernamePasswordJsonFilter");
        return getAuthenticationManager().authenticate(auth);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

内容的提问来源于stack exchange,提问作者huga721

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 01:25:27