问题描述
我正在尝试通过 MERN 实现 jwt 身份验证,并且在 nodejs 中我使用电子邮件激活链接将用户电子邮件和密码保存在 mongodb 中。这是我注册用户和激活用户的工作示例。我正在使用 sendgrid 发送电子邮件。
//for email verification test
signup = async (req,res) => {
const { username,email,password,passwordCheck,displayName } = req.body;
//validate
if (!username || !email || !password || !passwordCheck)
return res.status(400).json({
msg: "not all fields have been entered.",});
if (password.length < 8)
return res.status(400).json({
msg: "The password needs to be at least 8 characters long.",});
if (password !== passwordCheck)
return res
.status(400)
.json({ msg: "Enter the same password twice for verification." });
const existingUser = await User.findOne({ email: email });
if (existingUser)
return res
.status(400)
.json({ msg: "An account with this email already exists." });
const existingUserName = await User.findOne({ username: username });
if (existingUserName)
return res
.status(400)
.json({ msg: "An account with this username already exists." });
if (!displayName) displayName = email;
const token = jwt.sign(
{ username,displayName },process.env.JWT_SECRET,{expiresIn:'1000m'}
);
const msg = {
to: email,//receiver's email
from: "no-reply@test.com",// Change to your verified sender
subject: `Email verification link ${displayName}`,text: "testing from local",html: `<h2>Hi ${displayName}</h2> <br/>sends a message for verification test: http://localhost:3000/authentication/activate/${token}</p> <br/><p>Have a nice day</p>`,};
sgMail.setApiKey(process.env.SENDGRID_SECRET_API);
sgMail
.send(msg)
.then((result) => {
res.json({ message: "Email activation link has been sent" });
})
.catch((error) => {
console.error(error);
res.status(500).json("Error");
});
}
router.post("/register",signup);
userActivation = (req,res)=>{
const { token } = req.body;
if(token){
jwt.verify(token,function(err,decodetoken){
if(err){
return res.status(400).json({error:'Incorrect or expired link.'})
}
const { username,displayName }=decodetoken;
const newUser = new User({
username,displayName,});
newUser.save((err,success)=>{
if(err){
console.log("Error in signup with account activation",err)
return res.status(400).json({error:"Error activating account"})
}
res.json({
message:"signup Success!!"
})
});
} );
} else{
return res.json({error:"Something went wrong"})
}
}
router.post("/email-activate",userActivation)
在使用邮递员使用激活密钥保存用户时,在 mongodb 中,密码以纯文本格式保存。由于安全问题,我不希望它以纯文本格式保存。我希望它以加密方式保存并尝试使用以下代码:
userActivation = async (req,res) => {
const { token } = req.body;
if (token) {
jwt.verify(token,function (err,decodetoken) {
if (err) {
return res.status(400).json({ error: "Incorrect or expired link." });
}
const { username,displayName } = decodetoken;
console.log(password)
User.findOne({ email }).exec((err,user) => {
if (user) {
return res.status(400).json({ error: "Username with this email exists." })
}
const salt = bcrypt.genSalt();
bcrypt.hash(password,salt,(err,passwordHash)=>{
const newUser = new User({
username,password: passwordHash,});
console.log(password)
console.log(passwordHash)
newUser.save((err,success) => {
if (err) {
console.log("Error in signup with account activation",err);
return res.status(400).json({ error: "Error activating account" });
}
res.json({
message: "signup Success!!",});
})
})
})
})
}
}
当我启动服务器并尝试通过邮递员使用激活密钥登录时,它会向我发送激活链接。当我尝试通过激活链接中的邮递员发送发布请求时,邮递员显示 404 状态并显示“错误激活帐户”,并且节点索引显示以下错误:
The server has started on port: 5000
MongoDB connected
**the real password is showing undecoded**
**the real password is showing undecoded**
undefined
Error in signup with account activation Error: user validation Failed: password: Path `password` is required.
at ValidationError.inspect (C:\Myfiles\Reactjs\Projects\test-projects\node_modules\mongoose\lib\error\validation.js:47:26)
at formatValue (internal/util/inspect.js:731:31)
at inspect (internal/util/inspect.js:295:10)
at formatWithOptionsInternal (internal/util/inspect.js:1958:40)
at formatWithOptions (internal/util/inspect.js:1842:10)
at Object.value (internal/console/constructor.js:306:14)
at Object.log (internal/console/constructor.js:341:61)
at C:\Myfiles\Reactjs\Projects\test-projects\routes\userRouter.js:243:37
at C:\Myfiles\Reactjs\Projects\test-projects\node_modules\mongoose\lib\model.js:4863:16
at C:\Myfiles\Reactjs\Projects\test-projects\node_modules\mongoose\lib\helpers\promiSEOrCallback.js:16:11
at C:\Myfiles\Reactjs\Projects\test-projects\node_modules\mongoose\lib\model.js:4886:21
at C:\Myfiles\Reactjs\Projects\test-projects\node_modules\mongoose\lib\model.js:500:16
at C:\Myfiles\Reactjs\Projects\test-projects\node_modules\kareem\index.js:247:48
at next (C:\Myfiles\Reactjs\Projects\test-projects\node_modules\kareem\index.js:168:27)
at next (C:\Myfiles\Reactjs\Projects\test-projects\node_modules\kareem\index.js:170:9)
at Kareem.execPost (C:\Myfiles\Reactjs\Projects\test-projects\node_modules\kareem\index.js:218:3) {
errors: {
password: ValidatorError: Path `password` is required.
at validate (C:\Myfiles\Reactjs\Projects\test-projects\node_modules\mongoose\lib\schematype.js:1256:13)
at C:\Myfiles\Reactjs\Projects\test-projects\node_modules\mongoose\lib\schematype.js:1239:7
at Array.forEach (<anonymous>)
at SchemaString.SchemaType.dovalidate (C:\Myfiles\Reactjs\Projects\test-projects\node_modules\mongoose\lib\schematype.js:1184:14)
at C:\Myfiles\Reactjs\Projects\test-projects\node_modules\mongoose\lib\document.js:2502:18
at processticksAndRejections (internal/process/task_queues.js:75:11) {
properties: [Object],kind: 'required',path: 'password',value: undefined,reason: undefined,[Symbol(mongoose:validatorError)]: true
}
},_message: 'user validation Failed'
}
根据上面的尝试,代码无法对密码进行加密,因此无法将其保存在mongodb中。我在编码密码时做错了什么? 那么我该如何解决呢?
提前谢谢
解决方法
const passwordHash = bcrypt.hash(password,salt);
Here bcrypt.hash returning promise either your can use async/await or use .then().
userActivation = async (req,res) => {
const { token } = req.body;
if (token) {
jwt.verify(token,process.env.JWT_SECRET,function (err,decodeToken) {
if (err) {
return res.status(400).json({ error: "Incorrect or expired link." });
}
const { username,email,password,displayName } = decodeToken;
console.log(password);
User.findOne({ email }).exec((err,user) => {
if (user) {
return res.status(400).json({ error: "Username with this email exists." })
}
//Use genSaltSync when you donot want to use await or your can use await bcrypt.genSalt()
const salt = bcrypt.genSaltSync(10);
bcrypt.hash(password,salt,(err,passwordHash)=>{
const newUser = new User({
username,password: passwordHash,displayName,});
newUser.save((err,success) => {
if (err) {
console.log("Error in signup with account activation",err);
return res.status(400).json({ error: "Error activating account" });
}
res.json({
message: "signup Success!!",});
})
})
})
})
}
}
Try this code once just put await before bcrypt and made function async.