먼저
mongo
로 가서 데이터를 삭제 해 주었다.
use wetube
를 커맨드 입력해주고 db.sessions
,db.users
에서 remove({})
해주면 된다.
그리고 계정을 하나 만들어 본다. 다른건 다 작동하나 비밀번호 수정은 아직 안된다.
그전에 새로운 middelware
를 만들어 본다.
깃허브로 로근인하지 않은 사람들을 위한 middleware
이다.
깃허브로 로그인하면 무언가를 보여주지 않거나 보여주거나 하는 middelware
이다.
비밀번호를 가지고 있는 유저로부터 url
을 보호하는 middleware
를 만들 수도 있다.
if (req.session.user.socialOnly === true) {
return res.redirect("/");
}
이 코드를 여러 번 반복한다면 middleware
를 만들어도 된다. 현재는 아니니 그냥 둔다.
그리고 input
에 name
을 넣는걸 잊어서는 안된다. 그러면 백엔드에서는 읽을수 없다.
type
도 password
로 해주는거 잊지 않는다. 이제 이 name
들을 controller
에서 사용 할거다.
extends ../base
block content
form(method="POST")
input(placeholder="Old Password",name="oldPassword", type="password", requeired)
input(placeholder="New Password",name="newPassword", type="password", requeired)
input(placeholder="New Confirm Password",name="newPasswordConfirmation", type="password", requeired)
input(type="submit", value="Change Password")
바로 여기(pastChangePassword
)에서 사용 할거다.
export const postChangePassword = (req, res) => {
name
들을 req.body
안에서 가져온다.
const { oldPassword, newPassword, newPasswordConfirmation } = req.body;
그리고 현재 로그인한 사용자가 누군지 알아야 한다. 지금은 누가 비밀번호를 변경하려는지 모른다.
이 경우에는 postEdit
에서 사용 했던 방식을 쓰면 된다.
누가 로그인 했는지 알려면 user
의 id
를 확인해야 되기 때문이다.
그리고 비밀번호에 관련 된것들도 바꿔주면 된다.
export const postChangePassword = (req, res) => {
const {
session: {
user: { _id },
},
body: { oldPassword, newPassword, newPasswordConfirmation },
} = req;
session
에서 현재 로그인된 사용자를 확인하고 form
에서 정보를 가져오는거다.
form
에서는 사용자에게 누구냐고 묻지 않는다. 다른 사용자의 정보를 변경 할수 없어야 한다.
이제 사용자가 존재하는지 확인하고 async
를 하는거 잊지 말고 그리고 비밀번호를 변경해주면 된다.
새 비밀번호와 비밀번호 확인이 같은지 확인해야 한다.
export const postChangePassword = async (req, res) => {
const {
session: {
user: { _id },
},
body: { oldPassword, newPassword, newPasswordConfirmation },
} = req;
if (newPassword !== newPasswordConfirmation) {
return res.render("users/change-password", {
pageTitle: "Change Password",
errorMessage: "The new password does not match the confirmation.",
});
}
// send notification
return res.redirect("/");
getChangePassword
에서 썼던 코드를 가져와서 에러메세지를 추가 해주었다.
나중에는 이렇게 에러 메세지를 보내는 대신에 어떤
template
에도 보낼수 있는 알림을 사용 할거다.
block content
if errorMessage
span=errorMessage
그리고 change-password
에도 에러메세지를 만들어 준다.
테스트 해보면 잘 된다. 그러나 브라우저는 맞은걸로 알고 비밀번호를 저장하겠냐고 물어본다.
전에도 해봤던 status code
를 변경해야 한다.
return res.status(400).render("users/change-password", {
join
에서 에러가 생길때 했었다. 브라우저는 status code
를 주시하고 있다.
이번에 할건 기존 비밀번호가 정확한지 확인해야 한다.
bcrypt
로 했었다. 적용해 본다.
export const postChangePassword = async (req, res) => {
const {
session: {
user: { _id, password },
},
body: { oldPassword, newPassword, newPasswordConfirmation },
} = req;
const ok = await bcrypt.compare(oldPassword, password);
if (!ok) {
return res.status(400).render("users/change-password", {
pageTitle: "Change Password",
errorMessage: "The current password is incorrect.",
});
}
const ok = await bcrypt.compare()
넣어준다.
oldPassword
를 plain text
로 넣고 암호화된 password
도 넣어준다.
session
에 현재 로그인된 user
정보가 있다. user
는 password
정보를 포함한 object
이다.
그래서 사용자가 form
으로 보낸 비밀번호와 session
에 있는 비밀번호를 비교 한다.
if(!ok)
ok
가 아니면 똑같은걸 return
한다.
그리고 "기존 비밀번호가 일치하지 않다"로 에러 메세지를 바꿔 준다.
만약 모든게 일치한다면 비밀번호를 변경하도록 해준다. 그 전에 에러 메세지가 잘 나오는지 확인해 본다.
에러 메세지가 잘 나온다.
그 다음 단계는 비밀 번호를 변경해준다.
예전에 비밀번호를 저장하던게 있다.
User.js
에서
userSchema.pre("save", async function () {
this.password = await bcrypt.hash(this.password, 5);
});
비밀번호를 보내고 저장하면 저 함수가 비밀번호를 hash
해준다.
함수를 작동시키려면 두가지를 해줘야 한다. 하나는 pre save middleware
를 거치고
User.create
를 사용하는거다.
pre save middleware
가 비밀번호를hash
해주고 있다는걸 기억한다.
그리고 user.save()
를 해도 pre save middleware
를 작동시킬거다.
export const postChangePassword = async (req, res) => {
const {
session: {
user: { _id, password },
},
body: { oldPassword, newPassword, newPasswordConfirmation },
} = req;
const ok = await bcrypt.compare(oldPassword, password);
if (!ok) {
return res.status(400).render("users/change-password", {
pageTitle: "Change Password",
errorMessage: "The current password is incorrect.",
});
}
if (newPassword !== newPasswordConfirmation) {
return res.status(400).render("users/change-password", {
pageTitle: "Change Password",
errorMessage: "The new password does not match the confirmation.",
});
}
user.save();
하지만 이 경우에는 현재 user
가 없다. 그래서 먼저 user
를 찾아야 한다.
save()
함수를 써야 하니까 session
에서 로그인된 user
를 찾아야 한다.
그 user
를 찾으면 save()
함수를 사용 할수 있다.
if (newPassword !== newPasswordConfirmation) {
return res.status(400).render("users/change-password", {
pageTitle: "Change Password",
errorMessage: "The new password does not match the confirmation.",
});
}
const user = await User.findById(_id);
console.log("Old pw", user.password);
user.password = newPassword;
console.log("New unhashed pw", user.password);
await user.save();
console.log("New pw", user.password);
// send notification
return res.redirect("/");
};
const user = await User.findById
를 사용하여 session
에서 _id
를 찾을수 있다.
user
를 찾았으니 user.password = newPassword;
해주고 그 다음 user.save()
를 사용하는 거다.
user.save()
를 하면 pre save
가 작동한다. 이걸 작동시키려는 이유는 새로운 비밀번호를 hash
하기 위해서이다.
확인할수 있게 console.log(user.password)
를 해준다.
매 부분마다 확인할수 있게 console.log(user.password)
를 넣어 주었다.
그리고 save()
는 promise
이다. 그래서 await
를 붙여 주었다.
DB
에 무언가를 저장하는데는 시간이 걸려서 그렇다.
console.log
가 새 비밀번호와 hash
된 새 비밀번호를 보여줄거다.
예전 비밀번호도 확인해 본다. 테스트 해서 확인해 보겠다. 잘 된것같다. 콘솔에서도 확인해 본다.
Old pw $2b$05$k0gX8agEfRX0ufJ7H1lOWe99BpAEvMJ9qGPZZ389cRQHCJampVDl2
New unhashed pw 123
New pw $2b$05$.h1dcDGwaXZpF6iS9CC1Pehmb3kwZwOT9aeGozlsZAGAJm9yHgf/a
기존 비밀번호, hash
되지 않은 새 비밀번호 그리고 hash
된 새 비밀번호가 나온다.
그리고 사용자가 비밀번호를 바꾸면 로그아웃 시키는 기능도 넣어본다.
다시 로그인 하도록 로그아웃 시키는 거다.
const user = await User.findById(_id);
console.log("Old pw", user.password);
user.password = newPassword;
console.log("New unhashed pw", user.password);
await user.save();
console.log("New pw", user.password);
// send notification
return res.redirect("/users/logout");
테스트 해보니 비밀번호를 바꾸면 로그아웃 시킨다. 그러나 해당 강의에서는 안된다.
그래서 따라 해보기로 한다.
안되는 이유는 비밀번호 변경을 잘목했거나 기존 비밀번호를 session
에 있는 비밀번호와 비교해서 그럴수도 있다.
session
을 업데이트해주지 않아서 그렇다. session
에 있는 hash
된 비밀번호가 기존 비밀번호와 일치하는지 확인하고 있다.
그러니 session
을 업데이트 해준다.
const user = await User.findById(_id);
user.password = newPassword;
await user.save();
req.session.user.password = user.password;
// send notification
return res.redirect("/users/logout");
};
req.session.user.password = user.password;
이렇게 해준다.
왜냐하면 여기서는 비밀번호가 hash
돼 있기 때문이다. DB
와 session
두개의 저장소를 사용하고 있다.
session
에서 정보를 받으면 업데이트도 해줘야 한다.
form
에서 가져온 비밀번호랑 현재 로그인된 사용자의 비밀번호를 비교하고 있는걸 기억한다.
다른 방법도 있다.
export const postChangePassword = async (req, res) => {
const {
session: {
user: { _id },
},
body: { oldPassword, newPassword, newPasswordConfirmation },
} = req;
const user = await User.findById(_id);
const ok = await bcrypt.compare(oldPassword, user.password);
if (!ok) {
return res.status(400).render("users/change-password", {
pageTitle: "Change Password",
errorMessage: "The current password is incorrect.",
});
}
if (newPassword !== newPasswordConfirmation) {
return res.status(400).render("users/change-password", {
pageTitle: "Change Password",
errorMessage: "The new password does not match the confirmation.",
});
}
user.password = newPassword;
await user.save();
return res.redirect("/users/logout");
};
여기에 user
를 넣고 항상 user.password
를 해주는거다.
user
를 찾아서 DB
에 있는 가장 최근의 비밀번호를 사용하는거다.
session
에서 password
를 가져오지 않아도 된다. 똑같이 작동한다.