-
Notifications
You must be signed in to change notification settings - Fork 8
feat: 비밀번호 정책 추가 #435
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: 비밀번호 정책 추가 #435
Conversation
- 비밀번호는 영문, 숫자, 특수문자를 포함한 8자리 이상
Walkthrough
Estimated code review effort🎯 2 (Simple) | ⏱️ ~8 minutes ✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (3)
src/main/java/com/example/solidconnection/auth/dto/validation/Password.java (1)
10-20: 주석화와 확장성 개선 제안 (@documented, PARAMETER 타깃 추가, i18n 키 고려)
친절 메모 한 줄. 지금도 잘 동작하지만, 다음 3가지를 더하면 유지보수성이 좋아집니다.
- @documented 추가로 Javadoc/Swagger 등 문서 노출을 돕습니다.
- 컨트롤러 메서드 파라미터에도 직접 사용할 수 있도록 ElementType.PARAMETER 타깃을 포함합니다.
- 메시지를 하드코드 문자열 대신 메시지 키로 바꾸면 다국어(i18n) 대응이 쉬워집니다. 선택입니다.
제안 diff:
package com.example.solidconnection.auth.dto.validation; import jakarta.validation.Constraint; import jakarta.validation.Payload; +import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -@Target({ElementType.FIELD, ElementType.RECORD_COMPONENT}) +@Target({ElementType.FIELD, ElementType.RECORD_COMPONENT, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = PasswordValidator.class) +@Documented public @interface Password { - String message() default "비밀번호는 영문, 숫자, 특수문자를 포함한 8자리 이상이어야 합니다."; + // 선택: 메시지 키 사용 시 + // String message() default "{validation.password.policy}"; + String message() default "비밀번호는 영문, 숫자, 특수문자를 포함한 8자리 이상이어야 합니다.";src/test/java/com/example/solidconnection/auth/dto/validation/PasswordValidatorTest.java (1)
13-41: 테스트 보강: null/blank 허용 케이스 및 파라미터라이즈드 테스트 도입
친절 메모 한 줄. 정책 설계상 @password는 null/blank를 통과(true)시키고 @notblank로 필수값을 책임지므로, 해당 케이스를 명시적으로 검증하면 의도가 더 분명해집니다. 또한 유사 케이스는 파라미터라이즈드 테스트로 모으면 가독성이 좋아집니다.
- null/blank 허용 검사 추가:
@Test void 정상_패턴이면_true를_반환한다() { assertThat(validator.isValid("abcd123!", null)).isTrue(); } + + @Test + void null_또는_blank면_true를_반환한다() { + assertThat(validator.isValid(null, null)).isTrue(); + assertThat(validator.isValid("", null)).isTrue(); + assertThat(validator.isValid(" ", null)).isTrue(); // 공백만 포함 + }
- 선택: 각 invalid 케이스를 @ParameterizedTest로 합치면 중복을 줄일 수 있습니다.
src/main/java/com/example/solidconnection/auth/dto/validation/PasswordValidator.java (1)
9-16: 정규식 사전 컴파일로 성능/가독성 개선
친절 메모 한 줄. 매 요청마다 정규식을 컴파일하지 않도록 Pattern을 상수로 만들어 두면 성능과 가독성이 좋아집니다.제안 diff:
package com.example.solidconnection.auth.dto.validation; import jakarta.validation.ConstraintValidator; import jakarta.validation.ConstraintValidatorContext; +import java.util.regex.Pattern; public class PasswordValidator implements ConstraintValidator<Password, String> { + private static final Pattern PASSWORD_PATTERN = Pattern.compile( + "^(?=.*[A-Za-z])(?=.*\\d)(?=.*[!@#$%^&*()_+\\-={}\\[\\]|:;\"'<>,.?/`~])\\S{8,}$" + ); + @Override public boolean isValid(String value, ConstraintValidatorContext context) { if (value == null || value.isBlank()) { return true; } - - return value.matches("^(?=.*[A-Za-z])(?=.*\\d)(?=.*[!@#$%^&*()_+\\-={}\\[\\]|:;\"'<>,.?/`~])\\S{8,}$"); + return PASSWORD_PATTERN.matcher(value).matches(); } }선택: 최소 길이(예: 8)를 상수로 분리하거나, 어노테이션 속성(min 등)으로 노출하면 정책 변경에 더 유연합니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
src/main/java/com/example/solidconnection/auth/dto/EmailSignInRequest.java(1 hunks)src/main/java/com/example/solidconnection/auth/dto/EmailSignUpTokenRequest.java(2 hunks)src/main/java/com/example/solidconnection/auth/dto/validation/Password.java(1 hunks)src/main/java/com/example/solidconnection/auth/dto/validation/PasswordValidator.java(1 hunks)src/test/java/com/example/solidconnection/auth/dto/validation/PasswordValidatorTest.java(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (1)
src/main/java/com/example/solidconnection/auth/dto/EmailSignInRequest.java (1)
11-13: Bean Validation 어노테이션 순서 이슈 및 검증 순서 고정 제안확인 결과 프로젝트 내에
fail-fast설정은 발견되지 않았습니다.
Bean Validation은 기본적으로 모든 제약을 평가합니다.
하지만fail-fast모드가 활성화되면 첫 번째 검증 실패 후 즉시 중단되어 어노테이션 순서에 따라 결과가 달라질 수 있습니다.변경 사항은 다음과 같습니다:
- 원인 설명
- Bean Validation은 모든 제약을 평가합니다.
fail-fast모드 활성화 시 첫 번째 실패에서 검증이 중단됩니다.- 해결 옵션
fail-fast모드를 비활성화하여 모든 위반을 수집합니다.- 그룹 시퀀스를 도입하여 검증 순서를 명시적으로 고정합니다.
- 구현 예시
RequiredChecks,PasswordPolicyChecks인터페이스를 정의합니다.- DTO 필드에
@NotBlank(groups = RequiredChecks.class)와@Password(groups = PasswordPolicyChecks.class)를 적용합니다.- 클래스 상단에
@GroupSequence({EmailSignInRequest.class, RequiredChecks.class, PasswordPolicyChecks.class})를 추가합니다.프로젝트 설정을 직접 확인해 주시기 바랍니다.
| @Email(message = "이메일을 입력해주세요.") | ||
| String email, | ||
|
|
||
| @Password | ||
| @NotBlank(message = "비밀번호를 입력해주세요.") | ||
| String password |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
이메일 제약 조건/메시지 정비 및 비밀번호 검증 순서 고정
친절 메모 한 줄. 지금 이메일은 @Email만 있고 메시지가 “입력해주세요”로 되어 있어 의미가 어긋납니다. 아래처럼 @notblank로 “입력”을, @Email로 “형식”을 검증하도록 분리하는 것을 권장합니다. 또한 위 파일과 동일하게 그룹 시퀀스로 검증 순서를 고정하면 어노테이션 순서 민감도를 제거할 수 있습니다.
- 이메일 제약/메시지 정비:
- @Email(message = "이메일을 입력해주세요.")
+ @NotBlank(message = "이메일을 입력해주세요.")
+ @Email(message = "유효한 이메일 주소를 입력해주세요.")
String email,- 비밀번호 검증 순서 고정(선택): RequiredChecks → PasswordPolicyChecks 그룹을 위 파일과 동일하게 적용하세요.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| @Email(message = "이메일을 입력해주세요.") | |
| String email, | |
| @Password | |
| @NotBlank(message = "비밀번호를 입력해주세요.") | |
| String password | |
| @NotBlank(message = "이메일을 입력해주세요.") | |
| @Email(message = "유효한 이메일 주소를 입력해주세요.") | |
| String email, | |
| @Password | |
| @NotBlank(message = "비밀번호를 입력해주세요.") | |
| String password |
🤖 Prompt for AI Agents
In
src/main/java/com/example/solidconnection/auth/dto/EmailSignUpTokenRequest.java
around lines 9 to 14, the email validation currently uses only @Email with a
message that implies input is missing, which is misleading. Fix this by adding
@NotBlank with a message for input requirement and keep @Email for format
validation separately. Also, apply group sequence validation to both email and
password fields to enforce a fixed validation order, using RequiredChecks
followed by PasswordPolicyChecks for the password, matching the approach used in
the referenced file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Email 어노테이션은 빈 값이 들어와도 예외를 발생시키지 않는 거 같아서, 코드래빗 제안처럼 작성하는 게 좋을 것 같습니다 ! [참고]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!
whqtker
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
간단한 제안만 코멘트 달았습니다 !!!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
제가 알기로 어노테이션 순서가 상관없는 걸로 아는데
@password
@notblank(message = "비밀번호를 입력해주세요.")
String password
이상하게 이렇게 해야지만 정상 동작하고
@notblank(message = "비밀번호를 입력해주세요.")
@password
String password
이렇게 하니까 동작을 안하더라구요. 혹시 이유 아시는 분 계신가요?
구체적으로 어떤 상황에서 그런 건가요 ? 제가 해 봤을 땐 동일하게 나오는 거 같긴 합니다.
비밀번호가 빈 값인 경우가 엣지 케이스 같은데, 실행 순서 차이일까요 ...
- @notblank와 @Email을 함께 사용하도록
|
아 빈 값인 경우가 아니라 그냥 @password에 중단점도 찍어보고 로그도 찍어봤는데 중단점도 작동 안하고 로그도 안찍혀있더라구요! 성혁님이 바꾸셨을 땐 동작하셨나요? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (1)
src/main/java/com/example/solidconnection/auth/dto/EmailSignUpTokenRequest.java (1)
13-15: 비밀번호 제약 도입 OK, 순서 민감도 제거는 위 파일과 동일하게 적용 권장.
- 동일한 그룹 시퀀스(RequiredChecks → PasswordPolicyChecks)를 적용해 두 DTO의 일관성을 확보하세요.
- PasswordValidator의 공백 허용, fail_fast 비활성 또는 그룹 시퀀스 적용 중 하나(권장: 그룹 시퀀스)로 순서 의존성을 제거하세요.
- 필요 시 @password의 기본 메시지를 “영문/숫자/특수문자 포함 8자 이상” 등 정책을 명시적으로 안내하도록 정비하세요.
원하시면 이 DTO에도 그룹/시퀀스와 테스트를 동일하게 반영하는 커밋 패치를 제안드리겠습니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/main/java/com/example/solidconnection/auth/dto/EmailSignInRequest.java(1 hunks)src/main/java/com/example/solidconnection/auth/dto/EmailSignUpTokenRequest.java(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (4)
src/main/java/com/example/solidconnection/auth/dto/EmailSignInRequest.java (2)
3-4: 임포트 추가 적절합니다.
- 새 커스텀 제약(@password)과 표준 제약(@Email) 임포트 구성이 명확합니다.
- 불필요한 임포트가 없고, 컨벤션에 어긋남이 없습니다.
9-11: 이메일 검증 메시지 분리 적용 잘 하셨습니다.
| @Password | ||
| @NotBlank(message = "비밀번호를 입력해주세요.") | ||
| String password |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
비밀번호 정책 추가는 OK, “어노테이션 순서 민감도”는 그룹 시퀀스로 해결하세요.
-
- 현상 원인 설명: Bean Validation은 동일 필드의 제약 평가 “순서”를 보장하지 않으며, Hibernate Validator에 fail_fast가 켜져 있으면 첫 위반에서 즉시 중단합니다. 코드상 어노테이션 배치 순서가 검증 순서처럼 보일 수 있으나 이는 구현/리플렉션 차원에서 우연히 고정된 것처럼 보이는 효과입니다.
-
- 재현 조건 추정: PasswordValidator가 null/blank를 허용하지 않거나, fail_fast=true인 경우 어노테이션 배치에 따라 위반 메시지가 달라지거나 기대와 다른 동작처럼 보일 수 있습니다.
-
- 해법 1(권장): 검증 순서를 “그룹 시퀀스”로 고정합니다. RequiredChecks(입력 필수) → PasswordPolicyChecks(복잡도) 순으로 강제하면 어노테이션 배치와 무관해집니다.
-
- 해법 3(환경 설정): fail_fast를 사용하지 않거나(기본 false), 사용한다면 그룹 시퀀스를 반드시 함께 적용합니다.
아래는 DTO 필드의 그룹 지정 예시입니다.
- @Password
- @NotBlank(message = "비밀번호를 입력해주세요.")
+ @NotBlank(message = "비밀번호를 입력해주세요.", groups = RequiredChecks.class)
+ @Password(groups = PasswordPolicyChecks.class)
String password그리고 그룹/시퀀스 정의 예시입니다(패키지 내 공용 인터페이스로 두고 재사용 권장).
// 공용 그룹
public interface RequiredChecks {}
public interface PasswordPolicyChecks {}
// 검증 순서 고정
import jakarta.validation.GroupSequence;
@GroupSequence({RequiredChecks.class, PasswordPolicyChecks.class})
public interface ValidationSequence {}컨트롤러 바인딩 시 그룹 시퀀스를 사용하세요.
@PostMapping("/sign-in")
public ResponseEntity<?> signIn(@Validated(ValidationSequence.class) @RequestBody EmailSignInRequest req) { ... }PasswordValidator 보완 예시(입력 공백 위임):
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (value == null || value.isBlank()) return true; // 입력 여부는 @NotBlank에 위임
return PATTERN.matcher(value).matches();
}-
- 테스트 제안: 어노테이션 순서를 바꿔도 결과가 동일함을 보장하는 파라미터라이즈드 테스트를 추가하세요.
다음 스크립트로 환경/구현 상태를 점검해 주세요.
원하시면 그룹/시퀀스 도입 PR 보조 커밋과 테스트 케이스(순서 의존성 제거)를 바로 생성해드리겠습니다.
🏁 Script executed:
#!/bin/bash
# 1) fail-fast 설정 확인
rg -n -S 'hibernate\.validator\.fail_fast\s*[:=]\s*true' -g 'application*.{yml,properties}'
# 2) PasswordValidator의 공백 처리 확인
rg -n --hidden -S "class\s+PasswordValidator|isValid\(|isBlank\(" -A 8 -B 2
# 3) @Validated에서 그룹/시퀀스 사용 여부 확인
rg -n "@Validated\(" -A 2
# 4) @Password 사용 위치 전수 스캔
rg -n "@Password" -A 2Length of output: 12161
그룹 시퀀스로 검증 순서를 고정하세요
-
그룹/시퀀스 정의
•RequiredChecks와PasswordPolicyChecks인터페이스를 만들고
•@GroupSequence({RequiredChecks.class, PasswordPolicyChecks.class})로 순서를 지정합니다. -
DTO 필드에 그룹 지정
•EmailSignInRequest와EmailSignUpTokenRequest의password필드에
diff - @Password - @NotBlank(message = "비밀번호를 입력해주세요.") + @NotBlank(message = "비밀번호를 입력해주세요.", groups = RequiredChecks.class) + @Password(groups = PasswordPolicyChecks.class)
를 적용하세요. -
컨트롤러에 시퀀스 적용
•/sign-in등 관련 엔드포인트 메서드에
@Validated(ValidationSequence.class)를 붙여 그룹 시퀀스를 활성화합니다. -
순서 의존성 제거 테스트 추가
• 어노테이션 배치 순서를 바꿔도 동일한 검증 결과가 나오는지 검증하는 파라미터라이즈드 테스트를 작성하세요.
추가 참고
PasswordValidator는 이미null·빈 문자열을 허용하도록(return true) 구현되어 있어@NotBlank에 입력 여부 체크를 위임하고 있습니다.hibernate.validator.fail_fast설정은 기본값(false)으로 확인되어 있으며, 그룹 시퀀스 도입으로 모든 순서 이슈를 완벽히 제거할 수 있습니다.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| @Password | |
| @NotBlank(message = "비밀번호를 입력해주세요.") | |
| String password | |
| @NotBlank(message = "비밀번호를 입력해주세요.", groups = RequiredChecks.class) | |
| @Password(groups = PasswordPolicyChecks.class) | |
| String password |
🤖 Prompt for AI Agents
In src/main/java/com/example/solidconnection/auth/dto/EmailSignInRequest.java
around lines 13 to 15, you need to enforce a fixed validation order using group
sequences. Define two interfaces, RequiredChecks and PasswordPolicyChecks, then
create a ValidationSequence interface annotated with
@GroupSequence({RequiredChecks.class, PasswordPolicyChecks.class}). Annotate the
password field in EmailSignInRequest and EmailSignUpTokenRequest with the
appropriate groups to reflect these interfaces. In the controller methods
handling endpoints like /sign-in, add @Validated(ValidationSequence.class) to
activate the group sequence validation. Finally, add parameterized tests to
verify that changing the annotation order does not affect validation results.
whqtker
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
변경사항 확인했습니다 ~
아 빈 값인 경우가 아니라 그냥 @password에 중단점도 찍어보고 로그도 찍어봤는데 중단점도 작동 안하고 로그도 안찍혀있더라구요! 성혁님이 바꾸셨을 땐 동작하셨나요?
전 잘 되었던 거 같아요 원인이 뭘까요 ... ㅋㅋㅋㅋ
nayonsoso
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저도 두 순서로 모두 디버깅 해봤는데요!
{
"email": "[email protected]",
"password": "password"
}
이런식으로 해봤을 때, 둘 다 PasswordValidator 를 거쳐가는 것으로 확인했습니다
| import jakarta.validation.ConstraintValidatorContext; | ||
|
|
||
|
|
||
| public class PasswordValidator implements ConstraintValidator<Password, String> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
import와 public class 사이의 개행 2줄을
1줄로 해주시면 더 통일될 것 같습니다 😁
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🫡 ccc659e
|
인텔리제이의 버그였을까요,,, 뭘까요 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/main/java/com/example/solidconnection/auth/dto/validation/PasswordValidator.java(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (2)
src/main/java/com/example/solidconnection/auth/dto/validation/PasswordValidator.java (2)
1-6: [1] 스타일/구조는 깔끔합니다.
- 패키지/임포트/클래스 선언부 구성이 일관적입니다.
- 이전에 지적되었던 import와 class 사이의 개행도 1줄로 정리되어 통일감이 있습니다. 👍
8-12: @password 검증 순서 및 설정 확인 결과
검증 로직 설계
isValid메서드는null또는 blank를 만나면true를 반환하도록 설계되어 있어, 존재성 검증은@NotBlank에 위임됩니다.fail-fast 옵션 확인
application*.yml/application*.properties및ValidatorFactory설정 전체를 검색한 결과,fail-fast관련 속성이나 커스텀 ValidatorFactory 빈이 발견되지 않아 기본 순차 검증이 적용 중입니다.권장 대응 방안
- 현재 구조 유지: 필드에
@NotBlank와@Password를 함께 붙이는 간결한 패턴을 그대로 사용
- 조합 제약 적용:
@Password애노테이션 내부에@NotBlank를 포함하고@ReportAsSingleViolation을 달아 단일 메시지화
| return value.matches("^(?=.*[A-Za-z])(?=.*\\d)(?=.*[!@#$%^&*()_+\\-={}\\[\\]|:;\"'<>,.?/`~])\\S{8,}$"); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
❓ Verification inconclusive
[3] 정규식 퍼포먼스 개선과 정책 명확화 제안(사전 컴파일 + 유니코드 옵션)
- String.matches는 호출마다 패턴을 컴파일합니다. 성능과 가독성을 위해 Pattern을 static final로 사전 컴파일하는 편이 좋습니다.
- 현재 [A-Za-z]는 라틴 알파벳만 허용합니다. 한국어 등 유니코드 문자를 ‘문자’로 인정하려면 \p{L}을 고려하세요.
- 공백 허용 여부도 정책으로 확정 필요합니다. 지금은 \S 사용으로 공백(스페이스/탭 등)을 금지합니다.
- 참고: String.matches는 전체 매치를 전제하므로 ^/$는 중복이지만, 가독성 차원에서 유지해도 무방합니다.
적용 diff(ASCII 정책 유지, 사전 컴파일):
@@
-import jakarta.validation.ConstraintValidator;
-import jakarta.validation.ConstraintValidatorContext;
+import jakarta.validation.ConstraintValidator;
+import jakarta.validation.ConstraintValidatorContext;
+import java.util.regex.Pattern;
@@
-public class PasswordValidator implements ConstraintValidator<Password, String> {
+public class PasswordValidator implements ConstraintValidator<Password, String> {
+
+ private static final Pattern PASSWORD_PATTERN = Pattern.compile(
+ "^(?=.*[A-Za-z])(?=.*\\d)(?=.*[!@#$%^&*()_+\\-={}\\[\\]|:;\\\"'<>,.?/`~])\\S{8,}$"
+ );
@@
- return value.matches("^(?=.*[A-Za-z])(?=.*\\d)(?=.*[!@#$%^&*()_+\\-={}\\[\\]|:;\"'<>,.?/`~])\\S{8,}$");
+ return PASSWORD_PATTERN.matcher(value).matches();유니코드 ‘문자’ 허용(선택사항) 예시:
- 최소 하나의 유니코드 문자: (?=.*\p{L})
- 최소 하나의 숫자: (?=.*\d)
- 최소 하나의 특수문자: (?=.*[\p{Punct}\p{S}])
- 공백 금지 및 길이: \S{8,}
private static final Pattern PASSWORD_PATTERN = Pattern.compile(
"^(?=.*\\p{L})(?=.*\\d)(?=.*[\\p{Punct}\\p{S}])\\S{8,}$"
);추가로 테스트 케이스 보강을 권장합니다.
- 길이 경계(정확히 8자).
- 공백 포함/미포함.
- 한글/이모지 포함 시 정책 의도에 맞는지.
- 백슬래시(\) 등 현재 특수문자 집합에 없는 문자의 취급.
정규식 성능 최적화 및 정책 명확화 제안
- 정규식 패턴 사전 컴파일
- String.matches는 호출할 때마다 패턴을 컴파일하므로 매번 오버헤드가 발생합니다.
- 이를 방지하려면
static final Pattern으로 사전 컴파일하세요. - 예시 diff:
-import jakarta.validation.ConstraintValidator; -import jakarta.validation.ConstraintValidatorContext; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; +import java.util.regex.Pattern; public class PasswordValidator implements ConstraintValidator<Password, String> { - public boolean isValid(String value, ConstraintValidatorContext context) { - return value.matches("^(?=.*[A-Za-z])(?=.*\\d)(?=.*[!@#$%^&*()_+\\-={}\\[\\]|:;\"'<>,.?/`~])\\S{8,}$"); + private static final Pattern PASSWORD_PATTERN = Pattern.compile( + "^(?=.*[A-Za-z])(?=.*\\d)(?=.*[!@#$%^&*()_+\\-={}\\[\\]|:;\\\"'<>,.?/`~])\\S{8,}$" + ); + + public boolean isValid(String value, ConstraintValidatorContext context) { + return PASSWORD_PATTERN.matcher(value).matches(); }
- 유니코드 문자 허용 고려
[A-Za-z]는 라틴 알파벳만 허용합니다.- 한국어·한자·이모지 등 모든 언어 문자를 포함하려면
\p{L}을 사용하세요. - 예시:
private static final Pattern PASSWORD_PATTERN = Pattern.compile( "^(?=.*\\p{L})(?=.*\\d)(?=.*[\\p{Punct}\\p{S}])\\S{8,}$" );
- 공백 처리 정책 확정
- 현재
\S를 사용해 공백(스페이스·탭 등)을 금지하고 있습니다. - 실제 서비스 정책에 따라 공백 허용 여부를 명확히 결정하세요.
- 현재
- 테스트 케이스 보강
- 길이 경계(정확히 8자) 확인 테스트
- 공백 포함/미포함 시나리오
- 한글·이모지 포함 시 정책 일치 여부
- 백슬래시(
\) 등 특수문자 처리 검증
위 제안을 반영해 보시고, 패턴 변경이 전체 검증 로직에 미치는 영향을 함께 확인하세요.
🤖 Prompt for AI Agents
In
src/main/java/com/example/solidconnection/auth/dto/validation/PasswordValidator.java
around lines 14-15, the inline String.matches call compiles the regex on every
invocation and restricts letters to ASCII; precompile the regex as a static
final Pattern and use Pattern.matcher(value).matches() instead, replace [A-Za-z]
with \p{L} and use \p{Punct}\p{S} (or an agreed set of allowed special chars) to
allow Unicode letters and symbols, decide and document whether whitespace is
allowed (currently \S forbids it) and adjust the pattern accordingly, and add
unit tests for length boundary (exactly 8), whitespace allowed/forbidden,
Unicode letters (Korean/Chinese), emojis, and tricky special chars to validate
the new policy.
관련 이슈
작업 내용
해당 비밀번호 정책을 추가하였습니다!
특이 사항
제가 알기로 어노테이션 순서가 상관없는 걸로 아는데
이상하게 이렇게 해야지만 정상 동작하고
이렇게 하니까 동작을 안하더라구요. 혹시 이유 아시는 분 계신가요?
리뷰 요구사항 (선택)