Node.js Nodejs/mongodb-检查用户是否具有管理员权限(基于令牌的身份验证)

Node.js Nodejs/mongodb-检查用户是否具有管理员权限(基于令牌的身份验证),node.js,mongodb,authentication,express,jwt,Node.js,Mongodb,Authentication,Express,Jwt,在我的express/mongoose应用程序中,我定义了verifyOrdinaryUser函数来检查用户是否在服务器上经过身份验证。这很好,但是我在下面定义了verifyAdmin函数来检查用户是否也有管理员权限(我使用passport local mongoose模块来定义用户模式)。 正如您所看到的,用户的令牌在verifyOrdinaryUser()函数中被检查,它将加载一个名为decoded的新属性到请求对象,我正试图在verifyAdmin中重用该对象,而这正是我在postman中

在我的express/mongoose应用程序中,我定义了verifyOrdinaryUser函数来检查用户是否在服务器上经过身份验证。这很好,但是我在下面定义了verifyAdmin函数来检查用户是否也有管理员权限(我使用passport local mongoose模块来定义用户模式)。 正如您所看到的,用户的令牌在verifyOrdinaryUser()函数中被检查,它将加载一个名为decoded的新属性到请求对象,我正试图在verifyAdmin中重用该对象,而这正是我在postman中遇到以下错误的时候

{
  "message": "Cannot read property '_doc' of undefined",
  "error": {}
}
以下是

var User = require('../models/user');
var jwt = require('jsonwebtoken'); 
var config = require('../config.js');

exports.getToken = function (user) {
    return jwt.sign(user, config.secretKey, {
        expiresIn: 3600
    });
};

exports.verifyOrdinaryUser = function (req, res, next) {
    // check header or url parameters or post parameters for token
    var token = req.body.token || req.query.token || req.headers['x-access-token'];

    // decode token
    if (token) {
        // verifies secret and checks exp
        jwt.verify(token, config.secretKey, function (err, decoded) {
            if (err) {
                var err = new Error('You are not authenticated!');
                err.status = 401;
                return next(err);
            } else {
                // if everything is good, save to request for use in other routes
                req.decoded = decoded;
                next();
            }
        });
    } else {
        // if there is no token
        // return an error
        var err = new Error('No token provided!');
        err.status = 403;
        return next(err);
    }
};

exports.verifyAdmin = function(req,res,next){
    if(req.decoded._doc.admin !== true)  {
        return next(err);
    }else {
        return next();
    }
};
我肯定我把verifyAdmin函数搞砸了。 我觉得这个顺序很对 欢迎提出建议

多谢各位

编辑:中间件来自app.js

app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());

// passport config
var User = require('./models/user');
app.use(passport.initialize());
passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());

app.use(express.static(path.join(__dirname, 'public')));

app.use('/', routes);
app.use('/users', users);
app.use('/dishes',dishRouter);
app.use('/promotions',promoRouter);
app.use('/leadership',leaderRouter);

从评论中,我猜您在使用
app后会出现错误。请使用
ing
verifyAdmin
是因为调用了它。所以我们使用了
app.use(verifyAdmin())
而不是
app.use(verifyAdmin)

请注意,通过在没有任何参数的情况下调用此函数,
req
显然是
未定义的

我们要的是让Express打电话。我们只需要在某个地方填充这个函数

中间件很有趣


所以,简单地说,如果我跟踪这一点是正确的,我认为我们得到的是如下所示:

  • 我们有一个
    app.js
    (或者
    index.js
    或者
    server.js
    )来完成所有
    app.use

  • app.js
    已经设置了Passport,它负责身份验证

  • 我们还有一个模块,其中导出了以下中间件:

    • verifyOrdinaryUser
    • verifyAdmin
  • 让我们调用这个模块
    foo.js

  • 我们希望在我们只希望登录用户和管理员用户进入的位置使用
    verifyOrdinaryUser
    verifyAdmin
  • 我将继续并假设我们不希望用户除了登录页,
    app.use('/',routes)之外能够到达任何地方,未登录。因此,在这一行之后,让我们添加
    app.use(verifyOrdinaryUser)

    现在让我们假设只有管理员才能访问
    /users
    部分。为此,我们将把
    verifyAdmin
    中间件放在
    用户
    路由器前面。现在我们的代码如下所示:

    app.use('/', routes);
    
    // verifyOrdinaryUser will now be called before any middleware used AFTER this statement
    app.use(foo.verifyOrdinaryUser);
    
    // Call the verifyAdmin middleware BEFORE any middleware in the `users` router
    app.use('/users', foo.verifyAdmin, users);
    
    app.use('/dishes',dishRouter);
    app.use('/promotions',promoRouter);
    app.use('/leadership',leaderRouter);
    
    这段代码做了很多假设,但您应该能够调整它


    所有这些都说明,一些关于req.DECODE的信息。首先,doc似乎有点不对劲。Passport不应该处理
    verifyOrdinaryUser
    用户部分吗?

    我正在为不同的http请求分配不同的权限,这是在…Router.js(promoRouter.js等)文件中完成的,这就是我必须调用中间件的地方,如下所示

    .get(Verify.verifyOrdinaryUser, Verify.verifyAdmin, function(req,res,next){...}
    

    因此,在调用verifyOrdinaryUser之后,它将返回请求中解码的内容,我可以在调用verifyAdmin时使用这些内容。我调用verifyAdmin时没有首先检查用户是否经过身份验证,换句话说,首先调用verifyOrdinaryUser

    请求已解码。_doc.admin不工作

    但是你可以使用这个功能

    例如,当然,它对我有效:

    exports.verifyAdmin=函数(req、res、next){
    //检查令牌的标头、url参数或post参数
    var token=req.body.token | | req.query.token | | | req.headers['x-access-token'];
    //获取已解码的有效负载和标题“req.decoded.\u doc.admin”不工作
    var decAdmin=jwt.decode(标记,{complete:true});
    //解码令牌
    如果(令牌){
    //验证机密并检查exp
    验证(令牌,config.secretKey,函数(err,解码){
    if(err | | |!deadmin.payload._doc.admin){
    var err=new Error('您无权执行此操作!');
    err.status=403;
    返回下一个(错误);
    }否则{
    //如果一切正常,请保存以请求在其他路线中使用
    req.decoded=已解码;
    next();
    }
    });
    }否则{
    //如果没有代币
    //返回错误
    var err=新错误('未提供令牌!');
    err.status=403;
    返回下一个(错误);
    }
    
    };在同一课程中的位置a课程

    正如ForkInSpace所说,如果没有定义它,那是因为您的代码没有通过第一个中间件

    在第3周,我们没有使用.all(中间件)语法,而是为每个操作明确定义了所有中间件

    route('/')
    .get(Verify.verifyOrdinaryUser, function(req,res,next){...}
    .put(Verify.verifyOrdinaryUser, Verify.verifyAdmin, function(req,res,next){...}
    .post(Verify.verifyOrdinaryUser, Verify.verifyAdmin, function(req,res,next){...}
    
    在第4周,教授介绍了简化代码的.all(中间件)

    route('/')
    .all(Verify.verifyOrdinaryUser)
    .get(function(req,res,next){...}
    .put(Verify.verifyAdmin, function(req,res,next){...}
    .post( Verify.verifyAdmin, function(req,res,next){...}
    

    但是,如果您像我一样,没有复制/粘贴课程中提供的代码,而是键入它,您可能会错过这一点。需要更新你的全部代码才能工作

    我也在coursera班。其他答案所提供的详尽解释清楚地表明了对这些工具的深刻理解,但我认为对于这项任务来说,它们可能有些过火了。引用Jogesh教授在coursera留言板上对类似问题的回复:

    “您确定在调用verifyAdmin之前先调用了verifyOrdinaryUser吗?这两个必须一个接一个地链接起来

    从错误中,似乎req.decoded不可用。这意味着未调用verifyOrdinaryUser。此函数将decoded属性添加到req。“

    来自verify.js和app.js的代码看起来正确,不需要更改。但是,在路由器中调用verifyAdmin函数时,请确保在调用verifyOrdinaryUser后始终包含verifyAdmin,如下所示:

    .get(Verify.verifyOrdinaryUser, Verify.verifyAdmin, function(req, res, next) {
    
    因为req.decode是在verifyOrdinaryUser中建立的,所以当您在没有先调用verifyOrdinaryUser的情况下调用verifyAdmin时,您的
    .get(Verify.verifyOrdinaryUser, Verify.verifyAdmin, function(req, res, next) {
    
    exports.verifyAdmin = function(req, res, next){
        var isAdmin = req.decoded._doc.admin
        if (isAdmin) {
            return next();
        }
        else {
            // if user is not admin
            // return an error
            var err =  new Error ('You are not autorized to perform this   operation!');
            err.status =  403;
            return next(err);
    
        }
    }
    
     if (token) {
            // verifies secret and checks exp
            jwt.verify(token, config.secretKey, function (err, decoded) {
                if (err) {
                    var err = new Error('You are not authenticated!');
                    err.status = 401;
                    return next(err);
                } else {
                    // if everything is good, save to request for use in other routes
                    req.decoded = decoded;
                    next();
                }
    
    jwt.verify(token, config.secretKey, function (err, decoded) {
                if (err) {
                    var err = new Error('You are not authenticated!');
                    err.status = 401;
                    return next(err);
                } else {
                    // if everything is good, save to request for use in other routes
                      if (decoded._doc.admin) {
                      req.admin = true;
                    }
                    next();
                }
            });
    
    verifyAdmin = function(req,res,next){
        if (req.admin) {
          console.log("Admin active");
        next();
      }
        else {
          var error  = new Error('You do not have admin privileges!');
          error.status = 401;
          return next(error)
        }
      };
    
    .post(verifyOrdinaryUser, verifyAdmin, function(req, res, next){
    
    exports.verifyAdmin = function(req,res,next){
        if(req.decoded._doc.admin !== true)  {
            return next(err);
        }else {
            return next();
        }
    };
    
    {
      "message": "Cannot read property '_doc' of undefined",
      "error": {}
    }
    
    exports.verifyAdmin = function(req, res, next){
    // check header or url parameters or post parameters for token
    var token = req.body.token || req.query.token || req.headers['x-access-token'];
    
    // verifies secret and checks exp
    jwt.verify(token, config.secretKey, function (err, decoded) {
    if (err) {
      var err = new Error('You are not authenticated!');
      err.status = 401;
      return next(err);
    } else {
      // They are an admin
      if (decoded._doc.admin){
        return next();
      } else {
        // They are not an admin
        var err = new Error('You are not authorized to perform this operation!');
        err.status = 403;
        return next(err);
      }
    }
    });
    };
    
    exports.verifyAdmin = function (req, res, next) {
    
        if (req.decoded._doc.admin == true) {
            next();
        } else {
            // if the user is not admin
            // return an error
            var err = new Error('You are not authorized to perform this operation!');
            err.status = 403;
            return next(err);
        }
    
    };
    
    dishRouter.route('/')
    .get(Verify.verifyOrdinaryUser, function(req,res,next){
        //res.end('Will send all the dishes to you!');
        Dishes.find({}, function (err, dish) {
          if (err) throw err;
          res.json(dish);
        });
    })
    
    .post(Verify.verifyOrdinaryUser, Verify.verifyAdmin, function(req, res, next){
        //res.end('Will add the dish: ' + req.body.name + ' with details: ' + req.body.description);
        Dishes.create(req.body, function (err, dish) {
          if (err) throw err;
          console.log('Dish created!');
          var id = dish._id;
    
          res.writeHead(200, {
              'Content-Type': 'text/plain'
          });
          res.end('Added the dish with id: ' + id);
        });
    })
    
    .delete(Verify.verifyOrdinaryUser, Verify.verifyAdmin, function(req, res, next){
        //res.end('Deleting all dishes');
        Dishes.remove({}, function (err, resp) {
          if (err) throw err;
          res.json(resp);
        });
    });
    
    exports.verifyAdmin = function(req, res, next){
      if(req.decoded._doc.admin){
          return next();
      }else{
          var err = new Error('Not an Admin =.=');
          err.status = 401;
          return next(err);
      }
     };
    
    exports.getToken = function (user) {
        return jwt.sign({**data:user**}, config.secretKey, {
            expiresIn: 3600
        });
    };
    
    req.decoded.data.admin
    
    MAC:passport username$ npm start
    ...
    Connected correctly to server
    { data: 
       { _id: '59e011e9209e2613c5492b1d',
         salt: '...',
         hash: '...',
         username: 'username',
         __v: 0,
         admin: false },
      iat: 1508012930,
      exp: 1508016530 }
    
    GET /dishes 401 18.242 ms - 70
    
    exports.jwtPassport = passport.use(new JwtStrategy(opts,
        (jwt_payload, done) => {
            console.log("JWT payload: ", jwt_payload);
            User.findOne({_id: jwt_payload._id}, (err, user) => {
                if (err) {
                    return done(err, false);
                }
                else if (user) {
                    return done(null, user);
                }
                else {
                    return done(null, false);
                }
            });
        }));
    
    exports. verifyOrdinaryUser = passport.authenticate('jwt', {session: false});
    
    exports.verifyAdmin = function(params, err, next) {
        if (params.user.admin){
          return next();
        } else {
          var err = new Error('Only administrators are authorized to perform this operation.');
          err.status = 403;
          return next(err);
        }
    };
    
    ...
    .get(Verify.verifyOrdinaryUser, Verify.verifyAdmin, function(req,res,next){...}
    
    exports.verifyAdmin = ((req,res,next) =>{
            const name = req.body.username
            console.log(name)
            User.findOne({username: name},(err,user) => { 
                if(err) {
                    next(err)
                }
                else if(!user) {
                    next(new Error("user not found"))
                }
                else {
                    if(!user.admin) {
                        next(new Error("you are not an admin"))
                    }
                    else {
                        next()
                    }
                }                         
            });
        });