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 响应。
基本问题
我休息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 响应。