이전 파트에서
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
가 있는지 찾아 볼거다.
그리고 usernameExists
가 true
라면 (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 });
이런식으로 한다면 사용중인 username
과 email
을 동시에 가진 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
그런데 이미 username
을 req.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.",
});
}
그리고 User
를 create
하기전에 password
를 체크를 할거다.
만약 password
가 password2
와 같지 않다면 "비밀번호가 서로 일치하지 않는다."
는 메세지를 띄우게 만들었다. 이렇게 password
가 서로 일치 하는지 안하는지 체크하게 만들었다.
그리고
return res.render("join"
여기에 return
을 붙이고 있는데 return
을 쓰지 않으면 코드가 계속 진행 된다.
그래서 return
을 해줘야 function
을 끝낼수 있다. 이제 테스트를 해본다.
잘 작동한다. 사용중인 계정, 이메일 , 패스워드 일치 까지 확인 하고 있다.
이제 훨씬 꼼꼼하게 체크하는 join
페이지를 만들었다.
나중에 에러 메세지를 보기 좋게 만들어 본다. $or
을 쓰는 걸 배웠고, form
도 잘 사용하였다.
에러 메세지를 template
으로 보내고 있다.