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

for*_*ace 6 authentication mongodb node.js express jwt

在我的express/mongoose应用程序中,我正在定义verifyOrdinaryUser函数来检查用户是否在服务器上进行了身份验证.哪个效果很好,但是我在下面定义了verifyAdmin函数以检查用户是否也具有管理员权限(我使用passport-local-mongoose模块来定义用户模式).正如您所看到的,在verifyOrdinaryUser()函数中检查了用户的令牌,它会将一个名为decoding的新属性加载到我正在尝试在verifyAdmin中重用的请求对象,这就是我在邮递员中收到以下错误的时候.

{
  "message": "Cannot read property '_doc' of undefined",
  "error": {}
}
Run Code Online (Sandbox Code Playgroud)

以下是

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();
    }
};
Run Code Online (Sandbox Code Playgroud)

我确定我在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);
Run Code Online (Sandbox Code Playgroud)

eri*_*our 7

我也在课堂上.其他答案提供的详尽解释清楚地表明了对这些工具的深刻理解,但我认为它们对于这项任务可能有点过分.将Jogesh教授在课程留言板上的回复引用到具有类似问题的主题:

"你确定在调用verifyAdmin之前首先调用了verifyOrdinaryUser吗?这两个必须一个接一个地链接.

从错误中,看起来req.decoded不可用.这意味着未调用verifyOrdinaryUser.此函数将已解码的属性添加到req."

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

.get(Verify.verifyOrdinaryUser, Verify.verifyAdmin, function(req, res, next) {
Run Code Online (Sandbox Code Playgroud)

因为req.decode是在verifyOrdinaryUser中建立的,所以当您首先调用verifyAdmin而不使用verifyOrdinaryUser时,您的解码仍然是未定义的.您可以像其他答案建议的那样使您的verifyAdmin功能更加彻底,但同样,这项任务也没有必要.


Sau*_*rai 5

我也遇到了同样的问题.以下是verifyAdmin()的验证片段

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);
  }
}
});
};
Run Code Online (Sandbox Code Playgroud)


Tan*_*ner 1

从评论中,我猜您在app.useing 之后遇到的错误verifyAdmin是因为它被调用了。所以我们做了app.use(verifyAdmin())而不是app.use(verifyAdmin).

请注意,通过不带任何参数调用此函数,req显然会是undefined.

我们想要的是Express to do the calling. We just need to stuff this function in somewhere.

中间件很有趣。


回顾一下,如果我的追踪正确的话,我认为我们得到的结果如下:

  1. 我们有一个app.js(或者可能index.js是或者server.js)可以完成所有app.use路由器管道工作

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

  3. 我们还有一个导出了以下中间件的模块:

    • verifyOrdinaryUser
    • verifyAdmin

我们称这个模块为foo.js

  1. 我们想要在我们只希望登录用户和管理员用户去的地方使用verifyOrdinaryUserandverifyAdmin

我将继续假设我们不希望用户在未登录的情况下能够访问除登录页面之外的任何地方app.use('/', routes);。因此,在此行之后,让我们添加app.use(verifyOrdinaryUser)

app.use('/', routes);

// verifyOrdinaryUser will now be called before any middleware used AFTER this statement
app.use(foo.verifyOrdinaryUser);

app.use('/users', users);
app.use('/dishes',dishRouter);
app.use('/promotions',promoRouter);
app.use('/leadership',leaderRouter);
Run Code Online (Sandbox Code Playgroud)

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

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);
Run Code Online (Sandbox Code Playgroud)

这段代码做了很多假设,但您应该能够适应它。

话虽如此,关于 req.decoded._doc 的某些东西一开始似乎有点不对劲。Passport 不应该处理verifyOrdinaryUser用户部分吗?