기존에 로그인 Validator 적용을 한 바 있다. 하지만, BeanValidation을 배운 이후에, 로그인, 회원가입에서 BeanValidation을 부분적으로 적용이 가능할 것 같아 보였다.
BeanValidation 적용
아이디, 비밀번호의 유무, 길이 정도는 BeanValidation 적용이 가능하다.
Dto
@Data
public class LoginUserDto {
@NotBlank
@Size(min = 5)
private String username;
@NotBlank
@Size(min = 5)
private String password;
}
Controller
@PostMapping("/login")
public String login(HttpSession session, @Validated @ModelAttribute("user") LoginUserDto user, BindingResult bindingResult) {
log.debug("objectName={}", bindingResult.getObjectName()); // loginUserDto로 나오고 있었다. @ModelAttribute("user")로 해결
log.debug("target={}", bindingResult.getTarget()); // 정상적으로 LoginUserDto 인스턴스를 찾아옴.
log.debug("Input User DTO: {}", user);
/* 검증 실행 */
loginValidator.validate(user, bindingResult);
/* 검증에 에러가 발견되면, 폼을 보여줌. */
if (bindingResult.hasErrors()) {
log.debug("errors={}", bindingResult);
return "home/login";
}
/* 검증이 끝나면, 컨트롤러에서 로그인 처리 */
userService.login(session, user);
/* 로그인 후에 홈으로 리다이렉트 */
return "redirect:/";
}
Validator
@Override
public void validate(Object target, Errors errors) {
LoginUserDto user = (LoginUserDto) target;
String password = user.getPassword();
// 로그인 검증
User foundUser = getFoundUser(user);
if (rejectAuthentication(foundUser, password)) {
errors.reject(LOGIN_ERROR, null, null);
}
}
private User getFoundUser(LoginUserDto user) {
return userService.findByUsername(user.getUsername());
}
/**
* 받은 User 객체와 password 파라미터가 일치하는지 확인하고 실패할 시 결과 반환
*
* @param user : User 객체
* @param password : password
* @return : 일치하다면 true, 일치하지 않으면 false
*/
private boolean rejectAuthentication(User user, String password) {
if (user == null) {
return true;
}
return !user.getPassword().equals(password);
}
정리
정리하면, 흐름은 다음과 같다.
- BeanValidation으로 검증이 가능한 영역은 BeanValidation으로 검증
- 복잡한 검증은 Validator 사용하기