Ian*_*Ian 3 ejs node.js express passport.js
我有一个前端带有 EJS 的 Node Express 应用程序。
我有一个带护照的中间件功能,它在所有创建、编辑、删除路由之前运行。
function isLoggedIn(req, res, next) {
if (req.isAuthenticated()) {
if (req.user._id != "12345") {
res.redirect("/error");
}
return next();
}
res.redirect("/error");
}
Run Code Online (Sandbox Code Playgroud)
我能想到的最好的方法是通过 mongo db 中的用户 id 和 req.user._id 检查我的管理员用户是否是尝试访问该路由的用户
有没有更好的方法来处理管理员用户对路由和 html 组件的访问?
这对我来说基本上是正确的。重要的是要注意有两层:authentication和authorization。
身份验证实际上是一个布尔值:用户是否经过身份验证?你在那里有你的职能req.isAuthenticated()。这可能在逻辑上返回一个布尔值,true 或 false,表示用户是否经过身份验证(即:登录)。
授权可能可以采取多种形式,但实际上又是一个布尔值:该用户是否满足访问该资源的条件。
身份验证通常在中间件中得到很好的服务,中间件在“端点”之前运行,但授权并不那么简单,因为任何端点都可以允许或拒绝操作,或者它可以根据用户的权限做出不同的响应。
整个对话可能非常深入地讨论角色和权限。
我认为答案取决于应用程序。您的应用程序有两个要求:一是用户必须经过身份验证,二是用户可能需要是管理员。
答案就在附近:实现这一目标的最简单方法是什么?
在我看来,您会考虑 SOLID 原则,并注意到您有一个中间件,因此它应该有一个职责:检查用户是否经过身份验证。接下来,也许您应该有另一个名为的中间件isAdmin,它为需要此额外条件的每个端点运行。这确实是全部——额外的检查。你不应该污染你的isLoggedIn这些额外的东西污染您的中间件,因为它会使中间件的可重用性和可组合性降低。
中间件将是一个好主意,但将其作为每个需要管理检查的端点isAdmin内的函数也可能是个好主意。哪种方式更好?首先,哪种方式更简单。虽然代码较少,但仍然很容易理解。
因为这是角色和权限,是否有更强大的方法来跟踪哪些用户是管理员?如果您的代码运行类似于if (req.user._id === 12345) {},则需要特殊知识来记住代码中的这个位置,因此它有点脆弱并且“更有可能”失败。也许在您的用户表中添加一列可能是一个好主意,该列is_admin可以是null或0除了您的用户之外的每个用户都可以有1。那么你可以检查一下if (req.user.is_admin) {}。
这可能会导致我们使用如下中间件函数:
function isAdmin(req, res, next) {
if (req.isAuthenticated() && (req.user.is_admin === 1)) {
return next();
}
return res.redirect(403, "/error");
}
Run Code Online (Sandbox Code Playgroud)
您还可以执行诸如更改is_admin数据库列之类的操作,以代替role可能适用1于每个用户的操作,除了管理员用户(可能有2. 这将允许你做类似的事情:
function hasAuthorization(req, res, next) {
if (req.isAuthenticated() && (req.user.role >= 2)) {
return next();
}
return res.redirect(403, "/error");
}
Run Code Online (Sandbox Code Playgroud)
这样的逻辑可以让你拥有越来越多的权限角色:也许 1 是常规角色,2 是经理,3 是管理员,4 是超级管理员。如果用户的角色少于4,则他们没有权限。
在我看来,这种增加特权的想法很棒,但当您重构路线或角色时,可能会出现严重缺陷。您必须记住您所拥有的所有位置> 3并将其更改为> 4. 如果你忘记了任何一个,这会立即成为一种安全缺陷,所以我相信你理解我的论点。
而不是看到像<and 这样的运算符>。我宁愿看到对特定角色的检查,例如:
if ((req.user.role === 'ADMIN') || (req.user.role === 'MANAGER')) {}
Run Code Online (Sandbox Code Playgroud)
我们必须不断回到这个想法:什么是最简单的?制作一个isAdmin中间件然后将所有管理路由分组到中间件下是否更简单?或者将授权检查放在每个路由中更简单吗?
在这里检查这个例子:
import isAdmin from '../auth/isAdmin.js'
app.get('/admin', (req, res) => {
if (!isAdmin(req.user)) {
return res.redirect(403, '/error')
}
return res.render('admin')
})
Run Code Online (Sandbox Code Playgroud)
这可能需要更多工作,但也可能更细粒度,因此您拥有更多控制权。
app.get('/foobars', (req, res) => {
if (isAdmin(req.user)) {
return res.json(/* all foobar records from all accounts */)
}
if (isManager(req.user)) {
return res.json(/* all foobar records from the user's account */)
}
return res.json({ error: 'Insufficient privileges for this operation' })
})
Run Code Online (Sandbox Code Playgroud)
我最后的想法是,你应该有两个功能:一个检查用户是否经过身份验证,一个检查用户是否被授权。然后,您可以将它们堆叠在一个中间件或两个中间件中,或者在一个路由中。
我还认为你应该找到一种更强大的方法来检查用户是否是你自己。如果您将应用程序从一台计算机移动到另一台计算机,则下次填充用户表时用户 ID 可能会发生变化,因此这id不是锁定用户的有效方法。
| 归档时间: |
|
| 查看次数: |
3940 次 |
| 最近记录: |