将快速路由反向匹配到数据库条目
Reverse matching Express routes to database entries
我正在尝试为我的 Express 应用程序构建一种基于数据库的 ACL。我目前在数据库中有一个权限 table,其中包含类似的内容:
- 资源:
*
- 方法:
*
- 角色 ID:
1
- 允许:
true
- 资源:
/users
- 方法:
GET
- 角色 ID:
2
- 允许:
false
- 资源:
/users/id/*
- 方法:
GET
- 角色 ID:
2
- 允许:
true
我的目标是构建一个中间件来检查请求对象并根据数据库中的规则允许或拒绝路由。我的实际问题是,如何将 /users/id/1
与数据库条目 /users/id/*
匹配?如果我使用数据库条目作为我的正则表达式的基础,那么 /users/id/1
显然是匹配的,但是,我认为为每个请求提取和测试所有数据库条目是不切实际的。您认为根据请求的 URL 从数据库中获取正确规则的最佳方法是什么?
感谢您的宝贵时间!
好的,经过一些思考和研究,我发现你可以在 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()
})
})
}
我正在尝试为我的 Express 应用程序构建一种基于数据库的 ACL。我目前在数据库中有一个权限 table,其中包含类似的内容:
- 资源:
*
- 方法:
*
- 角色 ID:
1
- 允许:
true
- 资源:
/users
- 方法:
GET
- 角色 ID:
2
- 允许:
false
- 资源:
/users/id/*
- 方法:
GET
- 角色 ID:
2
- 允许:
true
我的目标是构建一个中间件来检查请求对象并根据数据库中的规则允许或拒绝路由。我的实际问题是,如何将 /users/id/1
与数据库条目 /users/id/*
匹配?如果我使用数据库条目作为我的正则表达式的基础,那么 /users/id/1
显然是匹配的,但是,我认为为每个请求提取和测试所有数据库条目是不切实际的。您认为根据请求的 URL 从数据库中获取正确规则的最佳方法是什么?
感谢您的宝贵时间!
好的,经过一些思考和研究,我发现你可以在 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()
})
})
}