우선은 로컬로 직접 회원가입을 진행한 회원일 경우에만 회원정보를 수정할 수 있도록 구현하였다. 추후 sns 로그인 유저는 이메일만 수정할 수 있도록 구현할 예정. aws 요금 이슈가 발생해서 프로필 사진은 aws가 아닌 다른 루트를 찾아봐야 할 것 같다
ㅠㅠ .............................................................................................................
다 울었으니 할 일을 해야지
일단 이메일과 닉네임을 변경하는 회원정보 수정 로직을 구현하고, 다른 페이지에서 비밀번호를 변경하는 내용을 구현하여 배포까지 완료했다. 저번에 했던 거라서 금방 슉 진행했다. 이메일 인증 라우터는 회원가입 시 구현했던 미들웨어와 라우터를 그대로 사용하여 코드를 절약했다.
프론트에서 이메일과 닉네임을 전달하는 부분은 그냥 axios.post에 데이터를 실어주는 것 뿐이라 다른 처리들이 좀 자잘하게 필요했다.(로딩창이라던지..) 회원정보를 저장할 때 만일 현재 유저의 이메일과 바꿀 이메일이 같을 경우 이메일은 그대로 유지하고, 다른 변동된 내용들만 변경할 수 있도록 해 주었다. 그리고 저번에 만든 모달 컴포넌트를 불러와 회원정보를 변경하였을 경우 2초 뒤 메인페이지로 이동한다는 알림창을 띄워주었다.
이메일 인증은 api를 새로 만들지 않고, 회원가입 때 만든 것들을 재사용했다. 그래서 새로 작성한 코드가 얼마 없다. id는 리덕스 스토어에 저장해놓은 id를 가져와서 사용했고, nikname은 setState를 할 때 기본값으로 리덕스에 들어있는 값을 바인딩해 주었다.
function onSave() {
// 이메일을 변경했을 경우, 이메일을 인증한 경우에만 이메일 저장 authResult = true 일때만
// 아니면 닉네임만 저장
let user = {
id: store.user.user_id,
email: authResult ? email : originallEmail,
nikname: nikname,
image: "변동없음",
};
axios
.post(`${process.env.REACT_APP_API_USER}/userUpdate`, user, {
withCredentials: true,
})
.then((response) => {
if (response.data.success) {
setModal(
"회원 정보를 변경하였습니다. 2초 뒤 메인페이지로 이동합니다."
);
setTimeout(() => {
navigate("/");
// eslint-disable-next-line no-restricted-globals
location.reload();
}, 2000);
}
});
}
백엔드의 라우터 역할도 간단하다! 전달받은 정보를 통해 유저를 찾고, 업데이트 하기만 하면 된다.
router.post("/userUpdate", (req, res) => {
User.findOneAndUpdate(
{
id: req.body.id,
},
{ nikname: req.body.nikname, email: req.body.email, image: req.body.image },
(err, doc) => {
if (err)
return res.json({
success: false,
err: err,
message: "유저 업데이트 실패",
});
return res.status(200).send({
success: true,
});
}
);
});
패스워드 검증 로직은 아래와 같이 구현했다. User 스키마에 bcrypt를 이용해 비밀번호를 검증하는 미들웨어를 만들고..
userSchema.methods.comparePassword = function (plainPassword, cb) {
bcrypt.compare(plainPassword, this.password, function (err, isMatch) {
if (err) return cb(err);
cb(null, isMatch);
});
};
checkPassword api에서 불러와 사용했다.
router.post("/checkPassword", (req, res) => {
User.findOne({ id: req.body.id }, (err, user) => {
if (err) {
return res
.status(400)
.json({ success: false, message: "유저 찾기 실패" });
} else if (user) {
user.comparePassword(req.body.password, (err, isMatch) => {
if (err) {
console.log(err);
return res.json({ success: false, message: "오류발생", err: err });
}
if (isMatch)
return res.json({
isMatch: true,
success: true,
message: "비밀번호가 일치합니다.",
});
else
return res.json({
isMatch: false,
success: false,
message: "비밀번호가 일치하지 않습니다.",
});
});
}
});
});
변경된 비밀번호는 .save를 통해 저장한다. User의 (... pre Save) 에서 비밀번호가 변경될 경우, 변경된 비밀번호를 암호화하여 db에 저장하는 함수를 작성해 주었기 때문에 save 객체를 만들어 save를 실행하기만 하면 되었다.
userSchema.pre("save", function (next) {
var user = this;
if (user.isModified("password")) {
console.log("비밀번호 변경중 ...");
bcrypt.genSalt(saltRounds, function (err, salt) {
if (err) return next(err);
// hash화된 비밀번호 저장
bcrypt.hash(user.password, salt, function (err, hash) {
if (err) return next(err);
console.log("해쉬화된 비밀번호:", hash);
user.password = hash;
next();
});
});
} else {
next();
}
});
router.post("/changePassword", (req, res) => {
User.findOne({ id: req.body.id }, (err, user) => {
if (!user) {
return res.json({
success: false,
message: "유저 정보를 찾지 못했습니다.",
});
} else {
user.password = req.body.password;
const updateUser = new User(user);
updateUser.save((err, userInfo) => {
if (err)
return res.json({ success: false, message: "비밀번호 변경 실패" });
return res.status(200).json({
success: true,
message: "비밀번호 변경 성공",
userInfo: userInfo,
});
});
}
});
});
댓글