1. ๋น๋ฐ๋ฒํธ ์ฌ์ค์
- ํ์๊ฐ์
์ด ์๋ฃ๋ ์ฌ์ฉ์๋ ๋น๋ฐ๋ฒํธ ์ฌ์ค์ ์ด ๊ฐ๋ฅํจ.
- ํ์๊ฐ์
์ ์
๋ ฅํ๋ ์ด๋ฉ์ผ์ผ๋ก ์ธ์ฆ์ฝ๋๋ฅผ ์ ์กํ๊ณ , ์ ํจํ ์ธ์ฆ์ฝ๋๋ฅผ ์
๋ ฅํ์ ๊ฒฝ์ฐ ์๋ก์ด ๋น๋ฐ๋ฒํธ๋ฅผ ์์ฑํ ์ ์์.
- ์ดํ ์๋กญ๊ฒ ์์ฑ๋ ๋น๋ฐ๋ฒํธ๋ ์ํธํ ์ฌ๋ถ๋ฅผ ํ์ธํ๊ณ , ์ํธํ๊ฐ ์งํ๋์๋ค๋ฉด DB์ ์ ์ฅ๋จ(๋ฎํ์ฐ๋ ๊ฒ).
1) ๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ ๋ผ์ฐํธ
// resetPassword.js
const express = require("express");
const router = express.Router();
const bcrypt = require("bcryptjs"); // bcryptjs ์ฌ์ฉ
const { User } = require("../../models/User");
// ๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ ๋ผ์ฐํธ
router.post("/reset-password", async (req, res) => {
const { email, newPassword } = req.body;
try {
const user = await User.findOne({ email });
if (!user) {
return res
.status(400)
.json({ success: false, message: "์ ํจํ ์ฌ์ฉ์๊ฐ ์๋๋๋ค." });
}
// ์๋ก์ด ๋น๋ฐ๋ฒํธ๋ฅผ bcryptjs๋ก ์ํธํํ์ฌ ์ ์ฅ
const hashedPassword = await bcrypt.hash(newPassword, 10);
console.log("์ํธํ๋ ์๋ก์ด ๋น๋ฐ๋ฒํธ:", hashedPassword);
// ์ํธํ๋ ๋น๋ฐ๋ฒํธ๋ฅผ user ๊ฐ์ฒด์ ํ ๋น
user.password = hashedPassword;
user.passwordResetCode = undefined; // ์ธ์ฆ์ฝ๋ ์ ๊ฑฐ
user.passwordResetExpires = undefined; // ์ธ์ฆ์ฝ๋ ๋ง๋ฃ ์๊ฐ ์ ๊ฑฐ
await user.save(); // ์ฌ์ฉ์ ์ ๋ณด ์ ์ฅ
// ์ ์ฅ๋ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๋ถ๋ฌ์์ ํ์ธ
const savedUser = await User.findOne({ email });
// ๋น๋ฐ๋ฒํธ๊ฐ ์ฑ๊ณต์ ์ผ๋ก ๋ณ๊ฒฝ๋์์์ ์๋ต
res.status(200).json({
success: true,
message: "๋น๋ฐ๋ฒํธ๊ฐ ์ฑ๊ณต์ ์ผ๋ก ๋ณ๊ฒฝ๋์์ต๋๋ค.",
});
} catch (error) {
console.error("๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ ์ค ์ค๋ฅ:", error);
res.status(500).json({
success: false,
message: "๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ ์ค ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค.",
});
}
});
module.exports = router;
2) ๋น๋ฐ๋ฒํธ ์ฌ์ค์ ์์ฒญ ๋ผ์ฐํธ
// resetPasswordRequest.js
const express = require("express");
const router = express.Router();
const { User } = require("../../models/User");
const {
sendPasswordResetEmail,
} = require("../../utils/sendPasswordResetEmail");
const crypto = require("crypto"); // ์ธ์ฆ์ฝ๋ ์์ฑ์ ์ฌ์ฉํ ๋ชจ๋
// ๋น๋ฐ๋ฒํธ ์ฌ์ค์ ์์ฒญ ๋ผ์ฐํธ
router.post("/request-reset-password", async (req, res) => {
const { email } = req.body;
try {
const user = await User.findOne({ email });
if (!user) {
return res
.status(400)
.json({ success: false, message: "์ ํจํ ์ด๋ฉ์ผ์ด ์๋๋๋ค." });
}
// ์ธ์ฆ์ฝ๋ ์์ฑ
const verificationCode = crypto.randomBytes(3).toString("hex");
user.passwordResetCode = verificationCode;
user.passwordResetExpires = Date.now() + 300000; // ์ธ์ฆ์ฝ๋ ์ ํจ ๊ธฐ๊ฐ 5๋ถ ์ค์
await user.save();
// ์ด๋ฉ์ผ๋ก ์ธ์ฆ์ฝ๋ ์ ์ก
await sendPasswordResetEmail(email, verificationCode);
res
.status(200)
.json({ success: true, message: "์ธ์ฆ์ฝ๋๊ฐ ์ด๋ฉ์ผ๋ก ์ ์ก๋์์ต๋๋ค." });
} catch (error) {
res
.status(500)
.json({ success: false, message: "์๋ฒ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค." });
}
});
module.exports = router;
3) ์ธ์ฆ์ฝ๋ ๊ฒ์ฆ ๋ผ์ฐํธ
// verifyCode.js
const express = require("express");
const router = express.Router();
const { User } = require("../../models/User");
// ์ธ์ฆ์ฝ๋ ๊ฒ์ฆ ๋ผ์ฐํธ
router.post("/verify-reset-code", async (req, res) => {
const { email, verificationCode } = req.body;
try {
const user = await User.findOne({ email });
if (
!user ||
user.passwordResetCode !== verificationCode ||
Date.now() > user.passwordResetExpires
) {
return res
.status(400)
.json({ success: false, message: "์ธ์ฆ์ ์คํจํ์์ต๋๋ค." });
}
// ์ธ์ฆ ์ฑ๊ณต ์
res.status(200).json({ success: true, message: "์ธ์ฆ์ ์ฑ๊ณตํ์์ต๋๋ค." });
} catch (error) {
res
.status(500)
.json({ success: false, message: "์๋ฒ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค." });
}
});
module.exports = router;
2. ํ์ ๊ฐ์ ์ ์ด๋ฉ์ผ ์ธ์ฆ ์ฌ์์ฒญ
- ๊ธฐ์กด์ ์ฝ๋๋ ํ๋ฒ๋ง ์ธ์ฆ์์ฒญ์ ๋ณด๋ผ ์ ์๊ฒ ๊ตฌํ๋์ด ์์์.
- ์ฆ, ์ฝ๋ ์ ์ก ๋ฒํผ์ ๋๋ฅด๋ฉด(ํ๋ก ํธ์์ ๊ตฌํ ์์ ) ๋ฒํผ์ ๋ ๋๋ฅด๊ฒ ๋๋ ์ฒ์ ์ ์ก๋ฌ๋ ์ธ์ฆ์ฝ๋๋ง ์ฌ์ฉ์ด ๊ฐ๋ฅํจ.
- ๋ฐ๋ผ์ ์ด๋ฉ์ผ ์ธ์ฆ ์ฝ๋๋ฅผ ์ฌ๋ฌ ๋ฒ ์ฌ์ ์กํ๊ณ , ๊ฐ์ฅ ๋ง์ง๋ง์ ์ ์ก๋ ์ธ์ฆ ์ฝ๋๋ฅผ ์ ํจํ ์ฝ๋๋ก ๊ฐ์ฃผํ๋ ๊ฒ์ผ๋ก ์ฝ๋ ์์ ํจ.
// signUp.js
// ํ์๊ฐ์
์ฒ๋ฆฌ ๋ฐ ์ด๋ฉ์ผ ์ธ์ฆ ์ฝ๋ ๋ฐ์ก
router.post("/", async (req, res) => {
const { email } = req.body;
try {
// ์ด๋ฉ์ผ์ด ์ด๋ฏธ ์กด์ฌํ๋์ง ํ์ธ
const existingUser = await User.findOne({ email });
if (existingUser) {
// ์ด๋ฉ์ผ ์ธ์ฆ์ด ์ด๋ฏธ ์๋ฃ๋ ์ฌ์ฉ์๋ผ๋ฉด ํ์๊ฐ์
์ ๋ง์
if (existingUser.isEmailVerified) {
return res
.status(400)
.json({ success: false, message: "์ด๋ฏธ ๊ฐ์
๋ ์ฌ์ฉ์์
๋๋ค." });
}
// ์ด๋ฏธ ์กด์ฌํ๋ ์ฌ์ฉ์๊ฐ ์ธ์ฆ์ฝ๋๋ฅผ ์ฌ์์ฒญํ ๊ฒฝ์ฐ, ์ธ์ฆ์ฝ๋ ์ฌ์ ์ก ์ฒ๋ฆฌ
const emailVerificationCode = crypto.randomBytes(3).toString("hex"); // 6์๋ฆฌ ์ฝ๋ ์์ฑ
existingUser.emailVerificationCode = emailVerificationCode;
existingUser.emailVerificationCodeExpires = Date.now() + 300000; // ์ธ์ฆ ์ฝ๋ ์ ํจ์๊ฐ 5๋ถ
...
}
// ์๋ก์ด ์ฌ์ฉ์์ ๋ํ ์ธ์ฆ์ฝ๋ ์์ฑ ๋ฐ ์ด๋ฉ์ผ ์ ์ก
const emailVerificationCode = crypto.randomBytes(3).toString("hex"); // 6์๋ฆฌ ์ฝ๋ ์์ฑ
const user = new User({
...req.body,
emailVerificationCode, // ์์ฑ๋ ์ธ์ฆ์ฝ๋ ์ ์ฅ
emailVerificationCodeExpires: Date.now() + 300000, // ์ธ์ฆ ์ฝ๋ ์ ํจ์๊ฐ 5๋ถ
});
...
});
3. ๊ฒฐ๊ณผ ๐
- ๋น๋ฐ๋ฒํธ ์ฌ์ค์
- ๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ ์
- ๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ ์ธ์ฆ์ฝ๋ ์ ์ก
- ์ธ์ฆ์ฝ๋ ์ ๋ ฅ ๋ฐ ์ฑ๊ณต
- ๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ