REST API - 过滤器、子实体或泄露信息真的那么糟糕吗?

REST API - filters, child entities or is leaking information really so bad?

基本问题

我休息API。为了这个例子,假设我有用户,他们可以是任意数量的组的成员,用户和组都可以拥有对象。

任何用户都可以按各种标准过滤对象:

/objects?color=green

/objects?created=yesterday

但只有给定组的成员才能按组所有权进行过滤:

/objects?groupId=1

并且只有实际用户才能按用户所有权进行过滤:

/objects?userId=55

现在有两种基本模式 - 一种可以使对象成为组的子实体,例如:

/groups/4/objects/1

其中 4 是组 ID,1 是对象 ID。另一种选择是并排放置组和对象:

/groups/4

/objects/1

使对象成为组 and/or 用户的子项将消除其他过滤选项 - 本质上,我有一个对象有多个路径。

真题

如果我想限制普通用户的访问权限,以便 he/she 只能访问 him/her 或 he/she 所属的组直接拥有的对象,它确实可以作为集合的过滤器 - 但实体级别呢?

如果我尝试:

/objects/9

但是该对象属于一个我不是其成员的组,我希望出现授权错误,而如果该对象根本不存在,我希望出现 "not found" - 这个,但是,这会泄露有关该书存在的信息,而且我还必须检索该对象才能确定用户是否有权查看它。

所以我想到了这个:

/objects/9?groupId=4

/objects/9?userId=55

在此,我可以根据组 ID 或用户 ID 初步决定授权,然后尝试检索具有附加限制的对象。

如果用户不是组 4 的成员,我可以说 not authorized,如果这本书不存在,我可以说 not found,意思不是那个该对象不存在,但该对象不存在于组 4 中。这个答案更清楚,而且我也不必先检索对象。

另一种方法是 return 授权错误,无论是由于我未被授权还是由于对象不存在。这个答案有点不准确,但可以减轻来电者的负担。

另一种可能是映射多个路径:

/objects
/groups/4/objects
/users/9/objects
/colors/green/objects

这看起来相当混乱,并且违反了单一概念单一路径的原则。

有人对此有任何实际见解吗?有什么理由(除了提到的那些)为什么一个或另一个更可取?

如果我的理解是正确的,每个对象都链接到(至少)一个组或(至少)一个用户,因此您不会遇到没有组或用户的对象的问题。

如果是这种情况,我看不到使用过滤器的意义,因为它在 REST 方式中没有意义,也不会给客户站点带来任何好处。

因此,正如您所建议的,您可以使用以下内容:

/groups/$groupID/objects/$objectID

/user/$userID/objects/$objectID

现在你的服务器应该检查客户端是否被授权 ("the user a member of the group" / "the current user") 给定 $groupID xor $userID

  • 如果未授权:甚至不检查对象是否存在。只给出未授权的错误。
  • 如果授权:给出标准响应代码

我看不到非授权客户获取资源是否可用的好处,因为这对他来说并不重要,因为他无法以任何方式访问它。正如您所建议的那样,它会导致信息泄漏 ,这可能会导致安全问题 (但这完全取决于您的 API 及其信息和用途)。


现在让我们来看看群组通话的场景:


用户 Arnold(组成员:1、2、3)想要访问成员组 3 的现有对象 7。

GET /groups/3/objects/7

响应: #200


用户 Arnold(组成员:1、2、3)想要访问他的成员组 2 中不存在的对象 55。

GET /groups/2/objects/55

响应: #404


用户 Arnold(组成员:1、2、3)想要访问非成员组 5 的现有对象 11。

GET /groups/5/objects/11

响应: #401


用户 Arnold(组成员:1、2、3)想要访问非成员组 5 的不存在的对象 19。

GET /groups/5/objects/19

响应: #401




对于用户对象:


用户 Arnold 想要访问他不存在的对象 56。

GET /user/arnold/objects/56

响应: #404


用户 Arnold 想要访问他现有的对象 13。

GET /user/arnold/objects/13

响应: #200


用户 Arnold 想要访问 Jon 的现有对象 77。

GET /user/jon/objects/77

响应: #401


用户 Arnold 想要访问 Jon 的不存在的对象 88。

GET /user/jon/objects/88

响应: #401


如您所见,如果客户端未授权,服务器仅响应 #401。另外,最好在正文中给出错误消息,例如Sorry, but you are not authorized to see content of user "Jon"Sorry, but you are not authorized to see content of group "ABYZX",这样客户就知道问题出在哪里了。

This seems rather messy and would violate the principle of having a single path for a single concept.

我不这么认为,因为也有不同的消息来源 (1) (3) and SO answers 说拥有多个路径或 URI 真的没问题。

Each resource in a service suite will have at least one URI identifying it.

它可以帮助客户了解授权过程,从而帮助他们浏览您的 API。

您描述的任何 URI 选项都可以。我更喜欢平面 URI,但这并不重要。

真正的问题是如何处理未经授权的请求。在这种情况下,我建议在所有情况下都使用 404 进行响应,包括资源存在但用户无权访问时。避免了信息泄露问题,完全兼容HTTP规范。

这个模式在逻辑上也是有道理的。在权限不足的用户看来,该资源不存在

如果您曾尝试在没有查看权限的情况下查看私人 Github 项目,您就会看到这种模式的实际应用。 Github 即使该项目确实存在,也会以 404 响应。