假设我有两个用户,A和B.
允许A访问所有可用资源,但B只能部分访问它们。
阻止B访问B没有权限的资源的正确方法是什么?
我应该创建某种白名单,只指定B可以访问的网址吗?
以下代码片段是我目前所拥有的。 它是一个中间件,用于检查是否允许每个请求访问特定的URL。
const ALLOWED_URLS = ['api/resource1', 'api/resource2', 'api/resource3'];
const sessionCheck = (req, res, next) => {
const url = req.originalUrl;
// check whether accessing URL is allowed
}
有没有比这更好的方法?
答案 0 :(得分:4)
您所询问的内容称为IAM(身份和访问管理)。 特定资源的角色,所有权和权限通常作为自己的业务域对象保留在数据库中。这是语言不可知的,并不是特定于节点或表达的。您不应该构建一个白名单URL。您要保护的资源位于数据库中。您应该将它们映射到权限对象,而权限对象又映射到用户。您的保护URL,保护资源。每个人都可以访问任何URL,但它们背后的资源是您正在保护的资源,这些规则/权限会存储在您的数据库中。
如果您正在寻找行业标准,那么这些IAM对象的常用名称/术语将保留在您的数据库中:
用户A的访问权限通常取决于他们拥有的角色或所属的群组。无论您是为用户A授予角色,将其置于授权组中,还是为其授予直接权限都无关紧要,这些分组可以减少重复,因此您可以一次传递或删除多个权限。但总体思路是一样的;您的资源存在于数据库中,您可以指定可以访问这些资源的必需或允许的角色,组和用户,以及将用户映射到组,角色等作为简单表条目。这意味着真正的授权逻辑不在Node或Express中,甚至不在您的webapp中,它内置于资源本身并与数据的检索方式相关联。
资源检索代码
当任何人请求给定资源时,如果用户未获得授权,则无论数据库类型如何,查询都将失败。这意味着您检索数据的方式必须直接与其授权方式相关联,而不是两个单独的步骤;这意味着您不应该获取资源,然后检查用户是否已获得授权,并且在获取资源之前不应检查用户是否已获得授权。最好的做法是融合/加入两者,这样除非得到授权,否则你无法获得资源,因为我们使用你的角色寻找资源,如果你没有合适的角色,我们找不到资源。
例如:
function getAccount(userId,accountId) {
makeSQLCall(userId,accountId)
}
SELECT *
FROM accounts a
WHERE a.accountId = accountId AND u.userId = userId
JOIN users u ON a.allowedRole = u.role
SQL无关紧要,因为其他技术可以做到这一点,但最后一行是最重要的(account.allowedRole = user.role)
。您实际上是使用users角色从数据库中提取资源,这样如果它们未经授权,则会失败并且不会返回任何数据。这也是您的基本/父数据检索功能,因此其他不了解授权的功能可以使用此功能,授权将在幕后处理。
表达伪代码
router.get('/api/resource1',function(req,res){
var user = utility.getUserFromRequest(req)
var resource = accountService.getAccount(user,req.body.accountId)
sendResponse(resource)
})
查看上面的代码,您的域模型内置了授权,而不是Web应用程序。如果上述请求的用户未获得授权,他们将不会收到任何数据。您必须在自己的业务中弄清楚用例是否足以返回空结果或者您是否需要返回401 HTTP错误代码。如果您需要通知非恶意用户他们未获得授权,您可以在运行isAuthoriized(user,accountId)
之前简单地执行accountService.getAccount
以方便用户界面。这种方法的优势在于,如果您或其他开发人员忘记检查isAuthorized 1st,则调用仍将不返回任何数据,因为isAuthorized()仅用于用户利益而非安全性。安全性位于域/ db层。
答案 1 :(得分:1)
通常,您将构建用户资源路由并在进行身份验证时验证其所有权及其对授权的权限。
E.g。
server.get('api/v0/products/:user', authMiddleware, (req, res, next) => {
// from the auth middleware comes a parsed token with payload
if (req.payload.user !== req.params.user) {
return res.status(401).send('not allowed')
}
// do action
})
另一种方法是仅访问与您的身份验证的有效负载匹配的数据库对象
该示例建议将JWT middleware与自定义属性user