OK,有點思考和研究後,我發現,你可以在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()
})
})
}