TypeError:无法在身份验证时读取未定义的属性“jwtoken”

Posted

技术标签:

【中文标题】TypeError:无法在身份验证时读取未定义的属性“jwtoken”【英文标题】:TypeError: Cannot read property 'jwtoken' of undefined at Authenticate 【发布时间】:2021-12-05 04:59:10 【问题描述】:

我正在尝试使用 jwt 对用户进行身份验证并发现此错误。这是一个 MERN 项目,在显示秘密页面之前,我必须验证我已将其数据存储在 MongoDb 中的用户。

VSCode 突出显示的其他错误是:

1.当我将鼠标悬停在._id (authentication.js)上时

const rootUser=await User.findOne(_id:verifyToken._id,"tokens.token":token)

类型'string | JwtPayload' 上不存在属性'_id'

2.当我将鼠标悬停在req.rootUser(app.js)上时

res.send(req.rootUser)

类型“Request<, any, any, ParsedQs, Record<string, any>>”上不存在属性 'rootUser'

我的代码如下:

app.js

const mongoose = require('mongoose')
const dotenv = require('dotenv')
const bcrypt = require('bcryptjs')
const jwt=require('jsonwebtoken')
const app = express()
const router = express.Router();
const port = 5000
const authenticate=require("./middleware/authenticate")

dotenv.config( path: './config.env' )
const DB = process.env.DATABASE;
app.use(express.json());
const User = require('./model/userSchema')



mongoose
  .connect(DB, 
    useUnifiedTopology: true,
    useNewUrlParser: true,

  )
  .then(() => console.log('Database connected.'))
  .catch(err => console.log(err));





app.get('/', (req, res) => 
  res.send('Hello World!')
  console.log("hey")
)
app.post('/register', async (req, res) => 
  const  name, email, work, phone, password, cpassword  = req.body;
  if (!name || !email || !work || !phone || !password || !cpassword) 
    return res.status(422).json( error: "Form Not Properly Filled" );
  
  try 
    const userExist = await User.findOne( email: email )
    if (userExist) 
      return res.status(422).json( error: "Email ALready Exists" )
    
    else if (password != cpassword) 
      return res.status(422).json( error: "Password does not match" )
    
    else 
      const user = new User( name, email, work, phone, password, cpassword )
      await user.save()
      res.status(201).json( message: "user registered successfully" )
    



   catch (error) 
    console.log(error);
  




)

//login route
app.post('/signin', async (req, res) => 
  try 

    let token;

    const  email, password  = req.body;
    if (!email || !password) 
      return res.status(400).json( error: "Please fill the data correctly" )
    
    const userLogin = await User.findOne( email: email )
    console.log(userLogin);
  
    if (userLogin) 
      const isMatch = await bcrypt.compare(password, userLogin.password)
      token = await userLogin.generateAuthToken();
      console.log(token)

      res.cookie("jwtoken",token,
        expires:new Date(Date.now()+25892000000),
        httpOnly:true

      )
      if (!isMatch) 
        res.status(400).json( error: "Invalid Credentials" )
      
      else 
        res.status(200).json( message: "Login Success" )
      
    
    else 
      res.status(400).json( error: "Invalid Credentials" )
    

   catch (error) 
    console.log(error)
  
)

//about page request

app.get('/about',authenticate,  (req, res) => 
  console.log("About")
  res.send(req.rootUser)
)
app.get('/forget', (req, res) => 
  res.cookie("harsh","test")
  res.send('Forget World!')
)

app.listen(port, () => 
  console.log(`Example app listening at http://localhost:$port`)
)

验证.js

const User=require("../model/userSchema")

const Authenticate=async (req,res,next)=>
try 
    console.log(req.cookies)
    const token=req.cookies.jwtoken;
    console.log("below")
    const verifyToken =jwt.verify(token,process.env.SECRET_KEY)
    console.log(verifyToken)
    const rootUser=await User.findOne(_id:verifyToken._id,"tokens.token":token)
    if(!rootUser)
        throw new Error("User Not Found")
    
    req.token=token;
    req.rootUser=rootUser;
    req.userID=rootUser._id;
    next();
 catch (error) 
    res.status(401).send('Unauthorized : No token provided')
    console.log(error)


module.exports=Authenticate;

userSchema.js

const mongoose=require('mongoose')
const bcrypt=require('bcryptjs')
const jwt=require('jsonwebtoken')

const userSchema=new mongoose.Schema(
     name:
         type:String,
         required:true,
     ,
     email:
        type:String,
        required:true,
    ,
    phone:
        type:String,
        required:true,
    ,
    work:
        type:String,
        required:true,
    ,
    password:
        type:String,
        required:true,
    ,
    cpassword:
        type:String,
        required:true,
    ,
    tokens:[
        
            token:
                type:String,
                required:true,
            
        
    ]
)


userSchema.pre('save' , async function(next)
    console.log("inside hash")
    if(this.isModified('password'))
        this.password=await bcrypt.hash(this.password,12)
        this.cpassword=await bcrypt.hash(this.cpassword,12)
    
    next();
)

userSchema.methods.generateAuthToken = async function()
    try 
        let token =jwt.sign(_id:this._id,process.env.SECRET_KEY)
        this.tokens=this.tokens.concat(token : token)
        await this.save();
        return token
     catch (error) 
        console.log(error)
    


const User=mongoose.model('USER',userSchema);
module.exports=User;

【问题讨论】:

【参考方案1】:

1。用户登录时生成 JWT 令牌

生成令牌并将此令牌与响应一起发送...

    router.post("/login", async (req, res) => 
      try 
        // checking username
        const user = await User.findOne( email: req.body.email );
        !user && res.status(401).json("Wrong Username");
    
        // checking password
        const bytes = CryptoJS.AES.decrypt(user.password, process.env.SECRET_KEY);
        const originalPassword = bytes.toString(CryptoJS.enc.Utf8);
    
        // If password not match return respond
        originalPassword !== req.body.password &&
          res.status(401).json("Wrong Password");
    
        // Creating Json Web Token
    
        const accessToken = jwt.sign(
           id: user._id, isAdmin: user.isAdmin ,
          process.env.SECRET_KEY,
           expiresIn: "5d" 
        );
    
        // stop sending password to respond
        const  password, ...info  = user._doc;
    
        // Returning User(info) , also sending accessToken
        res.status(200).json( ...info, accessToken );
       catch (err) 
        res.status(500).json(err);
      
    );

2。验证令牌中间件

创建此验证令牌函数,在您的路由中用作 MIDDLEWARE...

const jwt = require("jsonwebtoken");

function verify(req, res, next) 
  const authHeader = req.headers.token;
  if (authHeader) 
    const token = authHeader.split(" ")[1];
    jwt.verify(token, process.env.SECRET_KEY, (err, user) => 
      if (err) res.status(403).json("Token is not valid");
      req.user = user;
      next();
    );
   else 
    return res.status(402).json("You are not authorized");
  


module.exports = verify;

3。验证路由作为中间件

const verify = require("../verifyToken");

// CREATE
router.post("/", verify, async (req, res) => 
  if (req.user.isAdmin) 
    const newList = new List(req.body);
    try 
      const savedList = await newList.save();
      res.status(201).json(savedList);
     catch (error) 
      res.status(500).json(err);
    
   else 
    res.status(403).json("You are not allowed!");
  
);

// DELETE
router.delete("/:id", verify, async (req, res) => 
  if (req.user.isAdmin) 
    try 
      await List.findByIdAndDelete(req.params.id);
      res.status(201).json("The list has been deleted");
     catch (err) 
      res.status(500).json(err);
    
   else 
    res.status(403).json("You are not allowed!");
  
);

结论:-

    在用户登录时使用 jwt.sign 创建令牌... 在根目录下创建验证函数导出此函数... 需要在路由文件中使用此函数作为中间件...

【讨论】:

我根据你的编辑了我的代码,但我仍然得到 res.status(402).json("You are not authorized");来自中间件文件的错误。我试图找出它发生的原因,然后当我尝试在控制台上记录它时发现我的 authHeader 的值未定义,因此它向我发送 402 响应。我的令牌是使用您的代码生成并发送的 const password, ...info = user._doc; res.status(200).json( ...info, accessToken );

以上是关于TypeError:无法在身份验证时读取未定义的属性“jwtoken”的主要内容,如果未能解决你的问题,请参考以下文章

TypeError:无法读取未定义的属性“历史”

TypeError:无法读取 Vue 中未定义的属性“id”

TypeError:无法读取未定义 Passpor 错误的属性“名称”

NuxtJS Apollo 模块 TypeError:无法读取未定义的属性“$apolloHelpers”

TypeError:无法读取未定义的属性“标题”

vue-router.esm.js?8c4f:2181 TypeError:无法读取未定义的属性“loggedIn”