推荐使用自定义运行时异常PasswordMismatchException处理密码错误,继承RuntimeException无需强制捕获,配合BCrypt安全比对、全局异常处理器统一响应,并隐藏具体错误原因以防枚举攻击。

Java 中处理用户密码错误,推荐用自定义异常类明确区分业务逻辑错误,避免和系统异常混淆,也方便上层统一捕获、记录或返回友好提示。
定义密码错误的自定义异常
继承 RuntimeException(运行时异常),无需强制 try-catch,符合“非法登录”这类业务校验失败的语义:
public class PasswordMismatchException extends RuntimeException {
public PasswordMismatchException() {
super("用户名或密码错误");
}
public PasswordMismatchException(String message) {
super(message);
}
}
在验证逻辑中主动抛出
登录方法中比对密码失败时,直接抛出自定义异常,不返回布尔值或错误码,让控制流更清晰:
- 使用 BCrypt 或其他安全方式比对密码(不要明文比较)
- 用户不存在时建议用另一个异常(如
UserNotFoundException),与密码错误区分开 - 示例片段:
if (!BCrypt.checkpw(inputPassword, storedHash)) {
throw new PasswordMismatchException("密码不正确,请重试");
}
在 Controller 或 Service 层统一捕获处理
Spring 项目中常用 @ControllerAdvice 全局处理,返回标准错误响应:
立即学习“Java免费学习笔记(深入)”;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(PasswordMismatchException.class)
@ResponseBody
public ResponseEntity<ApiResponse> handlePasswordError(PasswordMismatchException e) {
return ResponseEntity.status(401).body(
ApiResponse.error("AUTH_FAILED", e.getMessage())
);
}
}
非 Spring 环境可在调用处 try-catch,记录日志并提示用户:“密码错误,请检查后重试”。
注意安全与体验细节
避免暴露过多信息,提升系统健壮性:
- 不要在异常消息中说明“密码错”还是“用户名错”,统一提示“账号或密码错误”,防止用户名枚举攻击
- 可结合登录失败次数做限流(如 5 次后锁定 15 分钟),但限流逻辑应独立于异常抛出
- 异常类可添加字段(如
failedAttempts、userId)便于审计,但不要存敏感数据


















