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