본문 바로가기
혼자서 개발새발

Java ) 비밀번호를 자체 검증하는 사용자 정의 애노테이션을 만들자!

by 휴일이 2024. 2. 6.

 

우리에겐 자동 검증을 해주는 @Valid 라는 좋은 애노테이션이 있다.

보통 String 문자열 같은 경우 @NotBlank 등을 주로 붙이는데,

비밀번호나 핸드폰 번호처럼 정해진 양식이 있는 경우에는 정규식으로 검증해야해서 애노테이션을 여러개 추가해야한다.

그게 귀찮고 + 좀 더 명확하게 처리하고 싶다면 사용자 정의 애노테이션으로 Valid 하자 !

 

 

 

 

나는 요로케 회원 가입 등에 사용할 DTO 에서

비밀번호를 검증할 애노테이션을 만들 것이당.

 

 

 

@Retention(RetentionPolicy.RUNTIME)
@Target({FIELD, PARAMETER})
@Documented
@Constraint(validatedBy = PhoneNumberMatcherValidator.class)
public @interface PhoneNumber {
    String message() default "핸드폰 번호는 010 으로 시작하며 이후 8자리로 이루어져야 합니다.";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

 

일단 내가 사용할 이름으로 애노테이션을 하나 만들어준다.

 

@Documented

javadoc 으로 문서를 생성할 때 현재 애노테이션에 대한 설명을 추가하는 그런 애노테이션인데..

보통 기본 애노테이션에 붙어있으니 붙여줬다.

@Constraint(validatedBy = {PasswordValidator.class})

이건 이따 설명할 건데 중요함. 이 @Password 애노테이션이 붙은 필드는 PasswordValidator 클래스를 사용해서 검증할 것임을 나타낸다.

@Target({FIELD, PARAMETER})

해당 애노테이션이 붙는 범위인데 아마 필드/파라미터에만 붙을 거 같아서 필드 범위로만 좁혀줬다.

@Retention(RUNTIME)

언제 실행되냐~ 인데 런타임시에 실행된다고 명시해주면 된다.

 

 

 

그러면 중요한 PasswordValidator 클래스를 만들어보자.

보통 합성 애노테이션 같은 경우는 여러가지 애노테이션을 붙여서 기능을 합성한 형태로 만들 수 있어가지고

1차원 적인 생각으로는 그냥 @NotBlank @Size 등을 붙여주면 되지 않나 생각했는데

Valid 같은 경우는 Validator 를 만들어서 검증해줘야함....ㅡㅅㅡ

 

 

 

@Component
public class PasswordValidator implements ConstraintValidator<Password, String> {

    private static final int MIN_SIZE = 6;
    private static final int MAX_SIZE = 20;
    private static final String regexPassword = "^(?=.*[A-Za-z])(?=.*[0-9])(?=.*[$@$!%*#?&])[A-Za-z[0-9]$@$!%*#?&]{" + MIN_SIZE + "," + MAX_SIZE + "}$";
    @Override
    public boolean isValid(String password, ConstraintValidatorContext context) {

        if (!StringUtils.hasText(password) || !password.matches(regexPassword)) {
            context.disableDefaultConstraintViolation();
            context.buildConstraintViolationWithTemplate(
                            MessageFormat.format("{0}자 이상의 {1}자 이하의 숫자, 영 대소문자, 특수문자로 이루어진 비밀번호가 필요합니다.", MIN_SIZE, MAX_SIZE))
                    .addConstraintViolation();
            return false;
        }
        return true;
    }
}

 

 

 

우리 서비스는 비밀번호가 6~20자 이고 영대소문자, 숫자와 특수문자를 포함하기 때문에

패스워드 필드가 존재하고 정규식 양식에 맞으면 true 를, 아니라면 false 를 반환하도록 만들었다.

false 를 반환할 경우 메시지 템플릿을 추가했는데,

이건 @Valid 가 핸들링 될 경우 에러 메시지로 들어갈 응답값이라고 보면 된다잉.

 

 

 

이렇게 만들고 나서

    @Builder
    public record UserSignUpDto (
            @NotBlank
            @Email
            String email,
            @Password
            String password

    ){}

 

    @PostMapping
    public void signUp(@RequestBody @Valid UserSignUpDto userSignUpDto) {
        userService.signUp(userSignUpDto);
    }

요로게 요로게 붙여주기만 하면?!

내가 지정한 양식으로 password 필드를 검증해준다 ㅎㅅㅎ 야르!

 

 

비슷한 방법으로 휴대폰 번호 등을 검증하는 애노테이션도 만들 수 있으니 참고 !!!!!

728x90