Skip to content
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

회원가입 유효성 검사 #96

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open

회원가입 유효성 검사 #96

wants to merge 4 commits into from

Conversation

sanoopark
Copy link
Contributor

@sanoopark sanoopark commented Aug 29, 2021

Animation13

유효성 검사를 클라이언트에서만 했을 때 가능한 변조를 막기 위해서 서버에서도 유효성 검사를 하도록 했습니다. 브라우저 콘솔에서 form.submit()을 하면 유효하지 않은 데이터가 서버로 전송되어 저장되는 것에 대한 방어 코드를 작성했습니다.

클라이언트 유효성 검사

  • 입력 중 이메일/비밀번호/닉네임 규칙 확인
  • 가입 버튼 클릭 시 모든 입력 폼 재확인 (개선 필요)
  • fetch로 이메일, 닉네임 중복 확인

서버 유효성 검사

  • 요청된 이메일/비밀번호/닉네임 규칙 확인
  • DB 탐색으로 이메일/닉네임 중복 확인

개선할 사항

  • checkDuplicateEmail()checkDuplicateName() 함수가 Promise { <pending> }을 반환해
    form.submit()이 호출되는 현상 → 중복체크는 클라이언트에서 현재는 되지 않고 서버에서만 되고 있습니다.

  • 모든 입력 폼을 공백으로 두고 가입 버튼을 클릭했을 때 '필수 정보입니다.' 문자열이 일부 폼에서만 출력되는 현상

  • 클라이언트와 서버에서 겹치는 로직(정규표현식 관련)을 공통 모듈로 만들 수 있는지 여부

@youngToMaturity
Copy link
Collaborator

확인했습니다! 클라이언트에서 POST 요청이 전송되고 서버에서 방어하고 있다는 것이 어떤 의미인가요?

@sanoopark
Copy link
Contributor Author

확인했습니다! 클라이언트에서 POST 요청이 전송되고 서버에서 방어하고 있다는 것이 어떤 의미인가요?

아직까지 원인을 모르게 form.submit()에서부터 /sign-up_process 로 데이터가 들어오는데, 라우터에서도 유효성 검사를 하고 있으니까 DB에 저장은 안 되는 상태입니다. 원래는 서버까지 안 넘어오고 form.submit()이 안 되는 게 맞습니다. 클라이언트에서도 유효성 검사를 하니까요.

Copy link
Collaborator

@42KIM 42KIM left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • 혹시 form.submit()에서 /sign-up_process로 데이터가 들어가는 게
    사용 불가능한 값을 입력한 뒤에 '이메일 회원가입' 버튼을 눌렀을 때도 데이터가 넘어간다는 말씀이신가요?
    코드를 직접 실행해보지 못하고 여쭤봐서 죄송합니다 ㅠ

  • 앗 async/await를 사용하셨군요. 저도 사용하려다가 지난 번에 카톡에서 얘기하면서 이 단계에서는 그냥 then으로 통일하는 게 낫지 않나 싶었는데, 그럼 저희 나머지 부분도 전부 async/await로 교체하는 게 나을까요?

  • 서버에서 이중 체크를 하려다보니 routes/auth.js에 함수가 엄청 필요해지네요. 이 부분도 따로 모듈로 관리하면 라우터 부분이 좀 더 깔끔하게 관리될 수 있을 것 같아요. 이건 나중에 routes 파일 전부다 싹 한 번 정리해야할듯....

  • 객체 디스트처럭처링으로 깔끔하게 정리해주셨군요!

  • 정규표현식 읽을 줄 몰라서 이번 주말에는 정규표현식을 공부해야겠습니다😭

@sanoopark
Copy link
Contributor Author

  • 혹시 form.submit()에서 /sign-up_process로 데이터가 들어가는 게
    사용 불가능한 값을 입력한 뒤에 '이메일 회원가입' 버튼을 눌렀을 때도 데이터가 넘어간다는 말씀이신가요?

사용 불가능한 값이 중복인 값이라면 말씀하신 게 맞습니다. 그 원인을 찾아보니까 checkDuplicateEmail(), checkDuplicateName() 함수가 false를 반환하는 줄 알았는데 Promise { <pending> } 을 반환하고 있었습니다. 그래서 focusout 될 때는 중복체크를 해서 문구를 출력하지만, 마지막에 가입 버튼을 클릭할 때는 중복인지 체크가 안 되고 있습니다. 어느 부분인지 코드에 코멘트 남겨놓겠습니다. 어떻게 고칠지 고민 중인데 좋은 방법 생각나시면 공유 부탁드립니다!

  • 앗 async/await를 사용하셨군요. 저도 사용하려다가 지난 번에 카톡에서 얘기하면서 이 단계에서는 그냥 then으로 통일하는 게 낫지 않나 싶었는데, 그럼 저희 나머지 부분도 전부 async/await로 교체하는 게 나을까요?

아, 제가 그 부분을 캐치 못 한 것 같아요. 프로미스로 통일해도 문제 없을 것 같습니다~

function checkDuplicateEmail() {
  const userInput = emailInput.value;
  return fetch(`http://localhost:3000/auth/check-duplicate-email`, {
    method: 'POST',
    body: userInput
  })
    .then(res => {
      if (res.ok) {
        return res.json();
      }
      throw new Error(`${res.status} Error`);
    })
    .catch(e => alert(e.message));
}

Comment on lines +17 to +44
async function checkDuplicateEmail() {
const userInput = emailInput.value;
const res = await fetch(`http://localhost:3000/auth/check-duplicate-email`, {
method: 'POST',
body: userInput
});
const isValid = await res.json();
if (!isValid) {
showIsValid(emailValidDiv, '이미 사용 중인 이메일입니다.');
}
return isValid;
}

async function checkDuplicateName() {
const userInput = nameInput.value;
const res = await fetch(
`http://localhost:3000/auth/check-duplicate-nickname`,
{
method: 'POST',
body: userInput
}
);
const isValid = await res.json();
if (!isValid) {
showIsValid(nameValidDiv, '이미 사용 중인 닉네임입니다.');
}
return isValid;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isValidtrue/false가 아닌 Promise { <pending> }인 상태입니다.

Comment on lines 110 to 113
checkDuplicateEmail() &&
checkDuplicateName()
) {
form.submit();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Promise { <pending> }가 리턴되기 때문에 form.submit() 되고 있습니다.

Copy link
Collaborator

@42KIM 42KIM left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분 관련 제 생각입니다

showIsValid(nameValidDiv, '이미 사용 중인 닉네임입니다.');
}
return isValid;
}
Copy link
Collaborator

@42KIM 42KIM Sep 2, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

async가 붙은 함수는 무조건 프로미스를 반환합니다. return 으로 프로미스가 아닌 일반값을 반환하더라도 해당 값은 프로미스로 감싸집니다.
상우님이 위에서 return isValid를 하고계시기 때문에 그 값이 true던지 false던지 모두 프로미스로 담겨서 return 됩니다.
따라서 아래 checkValidAll 함수 내부에서 이 함수에 기대하는 값인 true나 false를 반환하기 위해서는 .then을 통해 settled를 시켜야 할 것 같습니다.

그게 아니라면 애초에 return 값에 await fetch(~~~)를 할당하면 서버에서 넘겨주는 값이 바로 settled 되어서 return 될 거예요. 그게 await의 특징이니까.

자바스크립트는 await 키워드를 만나면 프라미스가 처리(settled)될 때까지 기다립니다. 결과는 그 이후 반환됩니다.

하지만 위 함수의 경우는 isValid를 통해 showIsValid를 실행시켜야 하니 바로 return await fetch(~~~)를 하게 되면 저 부분을 따로 빼서 실행하거나, 아니면 제가 위에 말한대로 checkValidAll 함수에서 resolve 하여 쓰시면 되지 않을까 싶습니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

설명 감사합니다. async가 무조건 프로미스를 반환하는지 이번에 알게 되었네요. 함수를 따로 빼는 것보다는 checkValidAll 함수에서 resolve 하는 것이 맞다고 판단해서 해당 부분 수정했습니다!

그리고 지금 에러 처리가 하나도 안 되어 있는데, 에러 처리랑 프로미스로 리팩토링은 주말에 진행하겠습니다~

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants