在先前我們建置好寄送 email 的服務後,我們接著來建立 resetPassword 的 function:
在 resetPassword function 中,我們會需要做以下幾件事:
在 AuthController 中,我們建立一個 resetPassword function:
resetPassword function:
exports.resetPassword = catchAsync(
async (req, res, next) => {
// 1. 透過加密的 token ,尋找儲存在 DB 中的 user
const hashToken = crypto
.createHash('sha256')
.update(req.params.token)
.digest('hex');
const user = await User.findOne({
tokenForResetPassword: hashToken,
passwordResetExpiresIn: { $gt: Date.now() }
});
// 上述的 $gt 是 greater than 的意思,詳細可以參考最後的小百科
// 2. 若 token 沒有過期 -> 開始設置 password,並且將 resetPassword 相關的參數重新設置成 undefined
// 2-1. 找不到 user 的情況: 代表 token 失效或是過期,回傳 400 錯誤
if (!user) {
return next(new AppError('Token has expired or is invalid.', 400));
}
// 2-2. 找到 user 的情況下,重設 password、
user.password = req.body.password;
user.passwordConfirmed = req.body.passwordConfirmed;
user.tokenForResetPassword = undefined;
user.passwordResetExpiresIn = undefined;
// 此處 save,並且不需要關閉 validate,因為我們需要驗證
await user.save();
// 3. 更新 changedPasswordAt (此處的程式碼我們會標示在下一個程式碼區塊中)
// 4. 登入 user 並且 send JWT
const signedToken = signToken(user._id);
res.status(200).json({
status: 'success',
token: signedToken
})
}
)
在 userModel.js 中,我們會建立一個 mongoose pre save middleware:
userSchema.pre('save', async function(next) => {
// 當 password 沒有被更新或是 Document 是 New 的時候,不用更新passwordChangedAt
if (!this.isModified('password') || this.isNew) return next();
// 設置 passwordChangedAt
// 不使用 this.passwordChangedAt = new Date.now(); 的原因: 因為存到 DB 的 passwordChangedAt timestamp 有可能會比發出 JWT 上面所記錄的 iat timestamp 還要大 (也就是時間有可能比較晚),所以需要做一個時間上的微幅調整
this.passwordChangedAt = Date.now() - 1000;
next();
});
還記得之前的 $gt
嗎 ?
在 MongoDB
中,$gt
的定義是:
選擇指定欄位的值大於(即 >)指定值的文件。
form 大致如下:
{ field: { $gt: value } }
(可以參考 MongoDB
官方網站: https://www.mongodb.com/docs/manual/reference/operator/query/gt/)
今天大致上介紹到這邊~
不知不覺參賽來到了第 27 天,感覺上還有一大堆內容沒寫完...
希望之後能順利完賽
Udemy Node.js, Express, MongoDB & More: The Complete Bootcamp 2023:
https://www.udemy.com/course/nodejs-express-mongodb-bootcamp
Hacksplaining:
https://www.hacksplaining.com/