我正在尝试为我的Express应用程序构建一种基于数据库的ACL。我目前在数据库中有一个包含类似内容的权限表:
*
*
1
true
/users
GET
2
false
/users/id/*
GET
2
true
我的目标是构建一个中间件,用于检查请求对象,并根据数据库中的规则允许或拒绝路由。我的实际问题是,我如何匹配,说/users/id/1
与数据库条目/users/id/*
?如果我使用数据库条目作为我的正则表达式的基础,那么/users/id/1
显然是匹配的,但是,我认为为每个请求提取和测试所有数据库条目是不切实际的。您认为根据请求的URL从数据库中获取正确规则的最佳方法是什么?
谢谢你的时间!
答案 0 :(得分:0)
好的,经过一番思考和研究,我发现你可以在MySQL查询中使用正则表达式,所以我想出了这个中间件(我正在使用Sequelize):
module.exports = function (req, res, next) {
// If a wildcard is in place, skip the rest
return models.Permissions.findAll({
where: {
resource: '*',
GID: req.session.role,
isAllowed: 1
}
}).then(function (result) {
if (result[0]) {
return next()
}
// If the URL contains more than one element, replace the last item with [item, *]
// to match eventual wildcards in the database entries
let urlItems = req.url.split('/').filter(Boolean)
let url = req.url
if (urlItems.length > 1) {
let lastItem = '[' + urlItems[urlItems.length - 1] + ', *]'
url = req.url.split('/')
url[url.length - 1] = lastItem
url = url.join('/')
}
let query = 'SELECT * FROM Permissions '
query += 'WHERE resource RLIKE "^' + url + '?$" '
query += 'AND GID = ' + req.session.role
return models.sequelize.query(query, {
type: models.sequelize.QueryTypes.SELECT
}).then(function (result) {
let policy = result[0]
function return403 () {
res.status(403).send('Forbidden')
}
// Forbid everything by default
if (!policy) {
return403()
return
}
let methods = policy.method.toUpperCase().split(' ')
// Forbid all methods which are not allowed
if (policy.method === '*' || methods.includes(req.method)) {
if (!policy.isAllowed) {
return403()
return
}
}
// When other methods are explicitly allowed, forbid everything else
if (policy.method !== '*' && !methods.includes(req.method) && policy.isAllowed) {
return403()
return
}
// Standard behaviour: allow explicitly allowed methods (or *) that are allowed.
next()
})
})
}