高性能 Web 应用程序如何控制对其内容的权限?

信息安全 oauth 授权 权限
2021-09-10 13:48:23

所以,我相信我理解像 OAuth 这样的授权标准背后的逻辑。OAuth 令牌包含有关用户的信息(姓名、角色等),我可以使用这些信息来保护我的应用程序

关于上一句的最后一部分,我有一个问题。假设我有一个包含 1000 篇文章的网络应用程序,我如何检查特定用户(基于他/她的 OAuth 令牌)是否有权访问某篇文章?我看到几个选项:

  1. 我将用户可以看到的所有文章 ID 存储在 OAuth 令牌中(例如 ID1、ID2、ID3 等);
  2. 相反,我也可以存储哪些用户可以访问文章(例如文章 1 可以被用户 1、2、3 阅读)。这就像一个 ACL;
  3. 对于每篇文章,我存储哪些角色可以访问该文章(例如文章 1 可以按角色阅读:读者)。这就像 RBAC;
  4. 根本不要保护您的内容,就像Facebook 似乎所做的那样(尽管他们确实保护了它,但他们只是在为您提供资源的直接 URL 之前检查您的朋友列表)。

澄清一下:我不是在寻找解释您可以将声明放入令牌本身的答案,这样您就不必点击数据库来检索您的声明(无状态)。我正在寻找应用程序后端如何使用这些声明来决定是否授予对某个内容项的访问权限的方法。


  • 选项 1 似乎是不好的做法,因为对于大型提供商而言,代币将变得无限大。
  • 如果大型提供商使用选项 2 或 3,他们将有大量的数据库命中(检查该用户是否可以访问该文章),这对性能不利。这种性能提升是 Facebook 和 Twitter 使用无状态授权而不是有状态授权的原因之一。我会假设内容级别的这种性能损失是使用选项 2 或 3 的障碍。
  • 那么,使用 4 是唯一可行的选择吗?

我看到的最后一个选项是使用选项 3,并结合大量缓存。由于内容权限不像用户权限那样短暂,所以这是我会选择的选项。但大型供应商(谷歌、Twitter、Dropbox 等)就是这样做的吗?它是如何实际实施的?


更新

有人告诉我关于Spring 的权限矩阵,你可以把它放在内存中,但我不确定这是否是要走的路。

2个回答

每篇文章都有一个关联的权限对象。该权限对象描述要评估的代码和任何可能的参数。大多数上下文都是相当规范的,例如在 Facebook 中,上下文可能是朋友。

因此,查看器的控件评估其附加规则:如果您是朋友,它会成功。这是一个相当快的操作。您可以更进一步,将特定数据附加到控件(我与除 Eve 之外的所有朋友或特定列表共享某些内容)。您还可以为查看器设置规则:编辑器可能会在其上下文中附加一个隐私控制器,该控制器对所有调用都返回 true。

我脑海中有两个很好的例子,可以看到它的一些工作原理。第一个是 Amazon AWS 权限:策略附加到用户和对象,它们描述了 AWS 上允许的操作。对于 AWS,规则从隐式拒绝开始。附加到用户和服务的所有规则都被评估,布尔逻辑是if permitted and not explicitly_denied. 查看 IAM 策略模拟器,以图形方式了解事物的评估方式。

另一个视图是Unix 的 PAM 服务,它允许您编写任何您想考虑用户的代码并将其结果标记为requiredsufficient或其他一些选项。

对于您的具体情况,您可能会为 RBAC 设置评估,针对特定的评估

顺便说一句,Facebook 和 Twitter 都使用有状态授权。至少在 Facebook 关于图像的情况下,对缓存图像的实际访问没有被检查以允许远程缓存,但它是在页面生成期间进行的。每次都是数据库调用。Facebook 上的典型页面加载可以生成超过 100,000 次数据库调用。简单的 KV 类型存储、内存缓存和强大的并行性确实有助于实现这一目标。

一些建议:

您应该在某处存储从登录用户那里获得的 oauth 令牌。因此,对于每个请求,您都可以验证此令牌。这会产生大量请求,并会减慢您的服务速度。您可以做的是,根据您保存在数据库中的此 oauth 令牌实现您自己的令牌,例如将此令牌客户端存储在 cookie 或会话 ID 中。

在后端,需要在每次请求时验证令牌。正如您可能已经看到的那样,google、airbnb 等只加载一些基本布局,其余部分加载 ajax 请求,这使整个页面看起来更快。因此,在每个请求中,您都必须添加当前令牌,当然还要在服务器端对其进行验证。

考虑到这个想法,您可以为需要快速登录的网站提供服务,因为它们大多是静态的。

关于访问列表的另一个想法。您还可以对用户进行分组,并按实际用户所在的组区分这些权限。

编辑:现在我肯定会选择一个安全的 API 和主要是标准的 HTML 页面,以便 API 可以决定交付什么。这具有快速响应的优势,您可以在后台进行所有检查。