我正在尝试为Express编写一个非常基本的中间件,检查用户是否具有访问资源所需的某个指定角色。我之前有另一个中间件,它为每个需要身份验证的路由(以及后续授权)的请求req
添加了一个用户对象。
因此,我定义了这样的授权中间件:
_ = require('lodash');
function authorize(req, res, next, roles){
// check to see if user has one of the allowed roles
if(_.contains(roles, req.user.role)){
req.authorized = true;
return next();
}
// otherwise, pass an error
return next(new Error("Unauthorized"));
}
每个用户对象上都有一个名为role
的属性,因此我使用_.contains(roles, req.user.role)
来确定允许的角色是否包含用户指定的角色。
但是,当我这样做时,我会在启动Express服务器后立即获得TypeError: Cannot read property 'role' of undefined
。这对我来说似乎很奇怪,因为我甚至没有提出请求,所以当然req.user
在那之前是不确定的。
有解决方法吗?
<小时/> 我如何使用此中间件的示例:
var app = express();
var router = express.Router();
router.get('/protected/:id', authorize(['ADMINISTRATOR', 'MANAGER', 'OWNER']), controllers.protected.retrieve);
答案 0 :(得分:1)
使用
注册路线时router.get(
'/protected/:id',
authorize(['ADMINISTRATOR', 'MANAGER', 'OWNER']),
controllers.protected.retrieve
)
authorize
方法会立即执行authorize(...)
,['ADMINISTRATOR', ...]
数组作为req
参数传递。因此,只要您运行代码并在用户对象不存在时死亡,就会调用它。即使它没有死在那,它也不会按预期工作。您正在混合中间件和工厂功能。
Express middleware是一个带有(req, res, next)
签名的函数,您不会自己执行。您需要将引用传递给这样的中间件函数,并且Express本身会在需要时根据请求执行它,即:
function authorize(req, res, next) {
...
};
router.get('/protected/:id', authorize, ...);
通过拆分 factory 和中间件功能,可以轻松创建参数化中间件功能(如您的情况):
// a factory function to create authorization middleware functions for given roles
function authorize(roles) {
// create and return an actual authorization middleware function
// to handle requests using the roles given when created
return function(req, res, next) {
if(_.contains(roles, req.user.role)){
req.authorized = true;
return next();
}
return next(new Error("Unauthorized"));
}
}
router.get(
'/protected/:id',
authorize(['ADMINISTRATOR', 'MANAGER', 'OWNER']),
controllers.protected.retrieve
)