[ React ] 회원가입 데이터 유효성 검사 방법

방충림·2023년 5월 18일
9

Code Repository

목록 보기
8/8
post-thumbnail

유효성 검사란?

회원가입을 할 때 보면 항상 여러가지 조건들이 걸려있다. 이러한 조건들로
입력한 데이터의 유효성을 검사하는 것을 유효성 검사(validation)라고 한다.

유효성 검사는 사용자가 제출한 데이터가 특정 조건을 충족하는지 확인하여 데이터의 유효성을 보장하고, 애플리케이션의 안정성신뢰성을 높이는 데 도움이 된다.

이러한 유효성 검사는 일반적으로 클라이언트 측에서 수행되며, JavaScript를 사용하여 구현할 수 있다.

이를 통해 사용자가 입력한 데이터를 즉시 확인하고 필요한 조건에 부합하지 않는 경우 사용자에게 적절한 메시지를 표시하거나 제출을 막을 수 있다.

※ 하지만! 서버 측에서도 유효성 검사를 수행해야 합니다. 클라이언트 측에서의 유효성 검사는 보조적인 역할을 하기 때문에, 보안상의 이유로 실제로 서버 측에서도 유효성을 다시 확인해야 합니다. 이를 통해 악의적인 사용자가 클라이언트 측에서의 유효성 검사를 우회하는 것을 방지하고, 안전한 데이터 처리를 보장할 수 있습니다.


UI 먼저 살펴보기

아래와 같은 회원가입 Form을 만들어 보았다. 완벽하진 않지만 충분히 많은 유효성을 검증해주고 있으므로, 내가 구현한 조건들과 구현 방법들을 공유하고자한다.

먼저 UI를 살펴보자

  • 아이디를 입력 받는데, "i" 모양 아이콘이 있는 걸 보니, 글자수 제한과 같은 추가 정규식 조건들이 있을 것으로 보인다. 중복확인도 해야한다.

  • 패스워드를 입력 받는데, "i" 모양 아이콘이 있는 걸 보니, 글자수 제한과 같은 추가 정규식 조건들이 있을 것으로 보인다.

  • 패스워드 확인을 통해 패드워드와 같은 값이 입력되었을 때만 통과할 수 있도록 되어있다.

  • 이름은 아무런 조건이 걸려있지 않다. (사실 특수 문자나 띄어쓰기들을 걸러낼 수 있도록 하면 더 좋겠다.)

  • 닉네임을 입력 받는데, "i" 모양 아이콘이 있는 걸 보니, 글자수 제한과 같은 추가 정규식 조건들이 있을 것으로 보인다. 중복확인도 해야한다.

  • 이메일은 조건이 없지만 이메일 인증을 해야한다. (포스팅 시점 아직 미구현)

  • 프로필 사진을 업로드할 수 있지만 선택 사항이다.

  • 개인정보수집 에 동의해야만 제출을 할 수 있다.

  • 선택사항인 프로필 사진을 제외한 모든 항목이 입력되고, 확인된 후에야 제출 버튼이 활성화된다.

  • 조건에 만족하는지 유무는 빨간글씨 혹은 초록글씨의 안내를 실시간으로 띄우고 있다.

  • 정규식의 대한 자세한 조건은 "i" 버튼에 마우스를 올려보면(hover) 확인할 수 있다.


고려사항

막상하려니 복잡해보인다. 무엇무엇을 고려해야할까?

큰 범주로 나누어 생각해보고 세부적인 조건을 따져보자.

제출 버튼 활성화를 위한 조건

  1. 필수정보 입력 유무 확인
  2. 정규식 충족 여부 확인
  3. 중복확인 (아이디, 닉네임만 해당)
  4. 비밀번호 & 비밀번호확인 일치 확인
  5. 이메일 인증 여부 확인 (미구현)
  6. 정보제공 동의 여부

별거 없어보인다.

이것을 어떻게 검증할 수 있을까?

코드를 보면서 설명하는게 효율적일듯하다.
입력값은 useState hook과 onChange prop를 통해 실시간으로 입력되고 관리되고 있으며, 각각의 프로퍼티의 역할은 주석과 같다.

 const [inputValue, setInputValue] = useState({
    id: "", // 입력된 아이디 데이터
    validId: false, // 아이디 정규식 충족 여부
    nonIdDuplication: false, // 아이디 중복확인 여부
    pw: "", // 입력된 패스워드 데이터
    validPw: false, // 패스워드 정규식 충족 여부
    pwCheck: "", // 입력된 패스워드 확인 데이터
    correctPwCheck: false, // 패드워드 데이터와 일치하는지 여부
    name: "", // 입력된 사용자 이름 데이터
    nickname: "", // 입력된 닉네임 데이터
    validNickname: false, // 닉네임 정규식 충족 여부
    nonNicknameDuplication: false, // 닉네입 중복확인 여부
    emailId: "", // 입력된 이메일 아이디 데이터
    emailAddress: "", // 선댁된 이메일 도메인 데이터
    validEmail: true, // 이메일 인증 여부 (미구현이라 true가 초기값, 추후 리팩토링 예정)
    profileImage: "", // 업로드된 프로필 이미지 (선택사항)
    agree: false, // 정보 제공 동의 여부
  });

음, 각각의 역할을 알았다. 그럼 이게 어떻게 충족되야 submit(제출)버튼이 활성화가 되는걸까?

&& 연산자의 단축평가(short-circuit evaluation) 기능을 활용하여 모든 조건이 참일때에만 true를 반환하는 식을 만든다.

  const submitRequirements = // 아래 조건을 모두 충족할 시 제출 버튼 활성화.
    inputValue.id && // 아이디가 입력되었는가?
    inputValue.validId && // 아이디가 정규식에 부합하는가?
    inputValue.nonIdDuplication && // 아이디가 중복되지 않았는가?
    inputValue.pw && // 비밀번호가 입력되었는가?
    inputValue.validPw && // 비밀번호가 정규식에 부합하는가?
    inputValue.pwCheck && // 비밀번호가 입력되었는가?
    inputValue.correctPwCheck && // 비밀번호 확인이 비밀번호화 일치하는가?
    inputValue.name && // 이름이 입력되었는가?
    inputValue.nickname && // 닉네임이 입력되었는는가?
    inputValue.nonNicknameDuplication && // 닉네입이 중복되지 않았는가?
    inputValue.emailId && // 이메일 아이디를 입력하였는가?
    inputValue.emailAddress && // 이메일 도메인 주소를  선택하였는가?
    inputValue.validEmail && // 이메일이 인증되었는가? (추후 리팩토링 예정)
    inputValue.agree; // 정보제공에 동의 하였는가

참고) 정규식은 다음과 같이 객체로 관리해주고 있다.

  // 정규식 모음 객체
  const inputRegexs = {
    // 아이디 : 문자로 시작하여, 영문자, 숫자, 하이픈(-), 언더바(_)를 사용하여 3~20자 이내
    idRegex: /^[a-zA-Z][a-zA-Z0-9_-]{2,19}$/,
    // 비밀번호 : 최소 8자 이상, 최소한 하나의 대문자, 하나의 소문자, 하나의 숫자, 하나의 특수문자를 포함, 공백 허용하지 않음
    pwRegex: /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=!])(?!.*\s).{8,}$/,
    // 닉네임 : 영어 대/소문자, 숫자, 한글 자모음 조합, 2~10자 이내
    nicknameRegex: /^[a-zA-Z0-9ㄱ-ㅎㅏ-ㅣ가-힣]{2,10}$/,
  };

이 조건을 모두 만족하여 submitRequirements에 true가 할당되면, 조건부 CSS에 따라 버튼의 색이 들어오면서, disabled 속성이 false가 되어 제출이 가능할 것이다.

   <button
            className={submitRequirements ? styles.allFilled : styles.submitBtn}
            onClick={handleSubmitId}
            disabled={!submitRequirements}
          >

또한 입력값을 실시간으로 판단해서 사용자에게 알려주기 위해, 경고 문구를 담을 객체를 만들어준다.

 // 조건에 부합하지 않는 경우 빨간글씨 경고 문구
  const [alertMessage, setAlertMessage] = useState({
    id: "",
    pw: "",
    pwCheck: "",
    nickname: "",
    email: "",
    agree: "",
  });

  // 조건에 부합할 경우 초록글씨 경고 문구
  const [passMessage, setPassMessage] = useState({
    id: "",
    pw: "",
    pwCheck: "",
    nickname: "",
    email: "",
    agree: "",
  });

경고 문구를 위한 세부적인 조건

위에서 언급한 경고문구를 오작동 없이 띄워주기 위해서는, 입력과정에서 발생할 수 있는 경우의 수를 모두 파악해야한다. 아쉽게도 많은 경우의 수가 존재하므로, 정신 바짝 차려야한다.

( 코드를 다 업로드 하고싶지만, 너무 길기때문에 어떠한 경우의 수들을 고려해야하는지만 작성하고, 코드는 하단 Github 주소를 첨부하겠다. )

case와 띄워줄 문구를 짝을 지어서 보여주겠다.

아이디

  1. 정규식에 부합하는 경우 : "조건을 충족하는 아이디 입니다. 중복을 확인해주세요."
    1) 정규식에 부합하면서 중복되는 아이디가 없는 경우 : "사용할 수 없는 아이디 입니다."
    2) 정규식에 부합하면서 중복되는 아이디가 있는 경우 : "이미 사용중인 아이디 입니다."
  2. 정규식에 부합하지 않는 경우
    1) 입력값이 존재하는 경우 : "사용할 수 없는 아이디 입니다."
    2) 입력값이 존재하지 않는 경우(다 지워졌을 경우) : "" (이걸 안하면 다 지워졌는데 문구가 남아있음)
    3) 정규식에 부합하지 않는데 중복 버튼을 누른 경우 : "사용할 수 없는 아이디 입니다."

주의할 점!
중복확인을 받은 이후에 아이디 입력값을 변경해버릴 가능성이 존재한다.
이 경우에 이미 nonIdDuplication는 true를 받았기 때문에 중복확인을 우회 할 수 있게된다.
따라서 입력값이 변경되면 nonIdDuplication가 다시 false 로 되도록 핸들링해야한다.

패스워드

  1. 정규식에 부합하는 경우 :"사용할 수 있는 비밀번호 입니다."
  2. 정규식에 부합하지 않는 경우
    1) 입력값이 존재하는 경우 : "사용할 수 없는 비밀번호 입니다."
    2) 입력값이 존재하지 않는 경우(다 지워졌을 경우) : "" (이걸 안하면 다 지워졌는데 문구가 남아있음)

패스워드 확인

  1. 비밀번호와 경우 : "비밀번호가 일치합니다."
  2. 비밀번호와 일치하지 않는 경우 : "비밀번호가 일치하지 않습니다."
  3. 입력값이 존재하지 않을 경우 (다 지워졌을 경우) : ""
    (존재하지 않을 때에도 일치하지 않는 건 사실이지만, 아직 입력도 안했는데 빨간 문구가 있는 것는 좋지 않다고 판단함)

주의할 점!
"패스워드"의 경우 "패스워드 확인"과 긴밀한 관계를 가지고 있기 때문에 보기와 달리 If문으로 만들면 조금 복잡할 수 있다.
.
이 둘은 각각 입력값이 변할 때마다 각각의 if문을 통과하고 있다. 때문에 if문을 섬세하게 짜지 않으면 경고문구에 오작동이 생길 수 있다.
.
예를들어 "패스워드"와 "패스워드 확인"이 일치한 상태에서, 패스워드의 값을 바꿔버리면 어떻게 될까?
"패스워드"의 if문에 "패스워드 확인"과 비교를 해주는 조건문이 없다면, "패스워드 확인"의 경고문구는 "비밀번호가 일치합니다." 상태로 계속 남아있을 것이다.
(중요) 이렇게 되지 않도록 "패스워드"의 if문에서도 패스워드 확인과 비교해주는 과정이 포함되어야한다.

닉네임 (아이디와 동일)

  1. 정규식에 부합하는 경우 : "조건을 충족하는 닉네임 입니다. 중복을 확인해주세요."
    1) 정규식에 부합하면서 중복되는 닉네임이 없는 경우 : "사용할 수 없는 닉네임 입니다."
    2) 정규식에 부합하면서 중복되는 닉네임이 있는 경우 : "이미 사용중인 닉네임 입니다."
  2. 정규식에 부합하지 않는 경우
    1) 입력값이 존재하는 경우 : "사용할 수 없는 닉네임 입니다."
    2) 입력값이 존재하지 않는 경우(다 지워졌을 경우) : "" (이걸 안하면 다 지워졌는데 문구가 남아있음)
    3) 정규식에 부합하지 않는데 중복 버튼을 누른 경우 : "사용할 수 없는 닉네임 입니다."

    주의할 점!
    중복확인을 받은 이후에 닉네임 입력값을 변경해버릴 가능성이 존재한다.
    이 경우에 이미 nonNicknameDuplication는 true를 받았기 때문에 중복확인을 우회 할 수 있게된다.
    따라서 입력값이 변경되면 nonNicknameDuplication가 다시 false 로 되도록 핸들링해야한다.

이메일

  1. 인증이 되지 않은 경우 : "이메일 인증을 진행해주세요"
  2. 인증이 완료된 경우 "완료된 경우"

    주의할 점!
    인증을 받은 이후에 이메일 입력값을 변경해버릴 가능성이 존재한다.
    이 경우에 이미 validEmail는 true를 받았기 때문에 인증을 우회 할 수 있게된다.
    따라서 입력값이 변경되면 validEmail가 다시 false 로 되도록 핸들링해야한다

profile
최선이 반복되면 최고가 된다.

0개의 댓글