Form Validation

0_CyberLover_0·2022년 4월 15일
0

Node.JS # 04

목록 보기
7/19

이전 파트에서 password를 어떻게 해시하는지 알아 보았다.

DB에 실제 password를 저장하면 안된다는걸 배웠다. 정말 위험하다.

혹시라도 어떤 사람이 유저가 사용하는 password를 볼수도 있다.

그러면 이제 유저가 로그인하고 싶을때 어떻게 password를 일치 여부를 확인하는지 알아 본다.

이번 파트에서는 userController를 조금 수정해 보도록 한다.

왜냐하면 계정 생성을 할때 중복되는 계정이 있으면 안되기 때문이다.

만약 이미 누군가 사용하고 있는 email로 계정 생성을 하려 한다면 어떻게 될까?

또는 같은 username으로 계정 생성을 한다면?

알다시피 username,email둘다 unique로 만들었다.

그러면 이미 존재하는 email,username으로 계정을 만들면 어떻게 되는지 본다.

이미 존재 하는 username으로 생성하면 당연히 안된다. 페이지가 오류가 난다.

콘솔을 확인하면 에러가 나오는데 살펴 본다.

MongoServerError: E11000 duplicate key error collection: wetube.users index: username_1 dup key: { username: "Cyber Lover" }

duplicate key error(중복된 키 에러)라고 나온다.

이미 존재하는 데이터를 저장하기 때문에 생긴 에러이다.

중복된 키로 저장하려 하니깐 에러가 발생하는거다.

DB가 잘 알아차리고 있다. 그런데 문제는 DB에서 이런 에러를 알려주는 것으로 끝나면 안된다.

직접 에러가 발생했는지 체크를 해줘야 한다. 에러가 발생 했는지 체크해주면 유저에게

에러 메세지를 보여줄수 있다.

그러면 DB가 에러를 보여준 것 대신에 DB에서 에러가 발생하지 않게 만들어 본다.

에러가 발생하면 DB에 저장하기 전에 그걸 catch 해준다.

DB에서 에러가 발생하는건 최후의 상황에서만 보여줄거다. 우선 코드에서 체크하게 만든다.

그래서 입력한 username이 이미 사용 중인지 부터 체크해준다.

export const postJoin = async (req, res) => {
  const { name, username, email, password, location } = req.body;
  const usernameExists = await User.exists({ username });
  if (usernameExists) {
    return res.render("join", {
      pageTitle: "Join",
      errorMessage: "This username is already taken.",
    });
  }

const userExists를 만들고, await를 써서 입력한 username을 가진 User가 있는지 찾아 볼거다.

그리고 usernameExiststrue라면 (username이 이미 사용 중이라면)

res.render("join")return한다. 그리고 에러메세지를 보낸다.

그리고 join.pug에서

block content 
    if errorMessage
        span=errorMessage

template를 표시 해준다. 이것 까지 작성해줘야 메세지가 뜬다. 그리고 새로고침 테스트 해보면 나온다.

그리고 이제 email도 똑같이 만들어 준다.

const pageTitle = "Join";

const emailExists = await User.exists({ email });
  if (emailExists) {
    return re.render("join", {
      pageTitle,
      errorMessage: "This email is already taken.",
    });

이렇게 해주면 된다. 그리고 pageTitle도 반복되길래 변수를 만들어 줬다.

이제 여기서 2가지의 에러를 체크하고 있다.

그래서 이미 사용중인 username또는 email일때 이렇게 2가지 경우를 말이다.

다시 한번 계정을 생성을 해본다. email이 중복되게 써본다.

이미 사용중인 email이라고 뜬다.

그리고 보다시피 중복된 코드가 많다. username을 체크하고 에러메세지를 보내는데

email에서도 체크하고 거의 똑같은 에러 메세지를 보내고 있다.

이렇게 다른 에러 메세지를 보여주고 싶다면 이렇게 만드는게 가장 좋은 방법일수 있다.

username을 체크하고 email체크하고 이렇게가 가장 좋은 방법일지도 모른다.

하지만 이렇게 중복으로 만들고 싶지 않다면 이렇게 하는 대신에 $or operator라는걸 쓸수있다.

$or operator를 쓰면 각 조건이 true일 때 실행 되게 만들수 있는데

이렇게 만든 이유는 이미 사용중인 username을 입력하거나 이미 사용중인 email을 동시에 입력 할수도 있기 때문이다.

const usernameExists = await User.exists({ username,email });

이런식으로 한다면 사용중인 usernameemail을 동시에 가진 user만 체크할수 있다.

그런데 $or로는 사용중인 username과 사용 중이지 않은 email을 가진 user를 찾을수 있다.

그래서 $or operator를 쓰려는 거다.

수정해 주도록 한다.

const exists = await User.exists({ $or: [{ username }, { email }] });
  if (usernameExists) {
    return res.render("join", {
      pageTitle,
      errorMessage: "This username/email is already taken.",
    });
  }

$or를 사용해 준다. 조건이 들어있는 배열을 써주면 된다. 자세한 사용법은

https://docs.mongodb.com/manual/reference/operator/query/or/#mongodb-query-op.-or

사이트에서 확인 할수 있다.

그러면 어떤 조건이 하나라도 true이면 해당 데이터를 찾아올거다.

예시를 보면

db.inventory.find( { $or: [ { quantity: { $lt: 20 } }, { price: 10 } ] } )

inventory에서 find()를 하고 있는데 quantity가 20보다 작거나 price가 10인 데이터를 찾고 있다.

이렇게 2가지 조건을 써준다. 하나는 req.body에 있는 username과 일치하는 User를 찾는거다.

username:req.body.username 그런데 이미 usernamereq.body에서 꺼냈으니

username:username이라고 할수 있다 그리고 이것도 줄여서 username이라고 쓴다.

그런 식으로 email도 마찬가지이다.

이제 이미 사용중인 username또는 email을 체크하게 만들었다.

그리고 메세지도 변경해 주었고 변수도 userExists에서 exists으로 변경해 주었다.

"이미 사용중인 username,/email 입니다." 로 변경해주었는데

유저가 조금 헷갈릴 수도 있을거다 어떤게 중복되는 건지 알수 없으니

그래서 아예 username을 쓰지 않고 email만 쓰는게 좋을 수도 있다.

어찌 되었든 $or에 대해 알게 되었다. 여러 조건에 하나만 해당되더라도 찾을수 있다.

테스트를 해본다. 잘 작동한다. 다음으로 넘어가기전에 한가지 더 짚고 간다.

password를 확인 할수 있는 input 을 하나 더 추가해야 될것 같다.

join.pug에서

input(placeholder="Password",name="password", type="password", requeired)
        input(placeholder="Confirm Password",name="password2", type="password", requeired)

이렇게 해주고

userController.js에서

const { name, username, email, password, password2, location } = req.body;
  const pageTitle = "Join";
  if (password !== password2) {
    return res.render("join", {
      pageTitle,
      errorMessage: "Password confirmation does not match.",
    });
  }

그리고 Usercreate하기전에 password를 체크를 할거다.

만약 passwordpassword2와 같지 않다면 "비밀번호가 서로 일치하지 않는다."

는 메세지를 띄우게 만들었다. 이렇게 password가 서로 일치 하는지 안하는지 체크하게 만들었다.

그리고

return res.render("join"

여기에 return을 붙이고 있는데 return을 쓰지 않으면 코드가 계속 진행 된다.

그래서 return을 해줘야 function을 끝낼수 있다. 이제 테스트를 해본다.

잘 작동한다. 사용중인 계정, 이메일 , 패스워드 일치 까지 확인 하고 있다.

이제 훨씬 꼼꼼하게 체크하는 join페이지를 만들었다.

나중에 에러 메세지를 보기 좋게 만들어 본다. $or을 쓰는 걸 배웠고, form도 잘 사용하였다.

에러 메세지를 template으로 보내고 있다.

profile
꿈꾸는 개발자

0개의 댓글