我应该在RESTful服务中拥有一个资源的多个视图/端点吗?

我应该在RESTful服务中拥有一个资源的多个视图/端点吗?,rest,authorization,entity-relationship,Rest,Authorization,Entity Relationship,比如说,我正在创建一个RESTful服务来处理网上仓库的订单 我希望允许客户创建帐户 我希望一个客户管理员能够在他们的办公室为其他用户创建帐户 我想允许客户用户创建订单 我希望网站管理员能够创建和管理所有客户帐户 我希望网站管理员能够创建和管理所有用户 我希望网站管理员能够创建和管理所有订单 鉴于这些要求。我最初的想法是以这种方式设计端点 # to request a new customer account /customers/request {POST} # create and vi

比如说,我正在创建一个RESTful服务来处理网上仓库的订单

  • 我希望允许客户创建帐户
  • 我希望一个客户管理员能够在他们的办公室为其他用户创建帐户
  • 我想允许客户用户创建订单
  • 我希望网站管理员能够创建和管理所有客户帐户
  • 我希望网站管理员能够创建和管理所有用户
  • 我希望网站管理员能够创建和管理所有订单
鉴于这些要求。我最初的想法是以这种方式设计端点

# to request a new customer account
/customers/request {POST}
# create and view customers - limited to admins
/customers {GET, POST}
# view customer info, update a customer
/customers/{customer_id} {GET, PATCH}
# create and view orders for a customer
/customers/{customer_id}/orders {GET, POST}
# view and update order for a customer
/customers/{customer_id}/orders/{order_id} {GET, PATCH}
我很有信心,这些路径是有意义的,并且遵循一般的restful思想。但是,我不确定如何处理用户端点。问题是,我希望客户管理员能够创建可以使用其客户帐户创建订单的用户。客户管理员在哪里发布来实现这一点?我有几个主意。 在这之后,我想到了这一点

# creation of users always done through this endpoint no matter what the
# authenticated user's role is
/users { GET, POST }
# associate user with customer
/customers/{customer_id}/user_memberships { GET, POST }
这种方法的问题是,客户帐户的管理员如何获取要与客户帐户关联的用户ID。将通过仅检索属于其客户帐户一部分的用户来筛选/用户上的任何GET请求。但是,由于用户将在成员资格之前创建,因此他们将永远无法查看该用户。 我还考虑过只使用两个端点来创建用户

# create a user for a customer account
/customers/{customer_id}/users {GET, POST}
# root users endpoint only accessible to admins
/users {GET, POST}
# return same user
/users/1
/customers/{customer_id}/users/1
它本质上归结为使用客户url前缀作为授权手段。两个端点使另一个端点失效似乎有点奇怪。如果根端点只是子资源端点的视图,该怎么办

# view all users in system - admin only
/users {GET}
# create & view admin users
/admin/users {GET, POST}
# create internal office users
/locations/{location_id}/users { GET, POST }
# create customer users
/customers/{customer_id}/users { GET, POST }
在这种情况下,我们仍然可以缓存子资源上的GET响应,因为它们不会更改,除非子资源的特定id上有POST或补丁/删除

这种风格似乎也适用于订单。管理员可以查看所有订单,即使它们在技术上属于客户

# admin can view all orders
/orders?customer_id=1234
/orders
我有点喜欢根资源是子资源视图的想法,允许基于url进行更轻松的授权

所以,我想在这一切之后,我真正的问题是:


即使其中一个端点只是子资源的聚合视图,并且不允许通过该端点创建资源,但有多个端点表示同一资源是否是一个问题?

根据我的理解,例如,您希望该客户仅查看其用户,而不能创建仅由管理员创建的用户,因此,这也可以使用spring security来实现,这肯定会造成问题,因此您必须根据自己的需求对客户进行分类。

您不应该将API的设计、REST原则和授权需求混为一谈。您应该以以下方式设计API:

  • 易于使用
  • 易于维护
  • 易懂
RESTful API设计方法试图解决这些不同的问题。RESTful方法是识别您拥有的对象、它们的状态以及它们可能的转换

这就是它停止的地方。现在,您想知道授权。您希望能够根据用户是谁(管理员、客户等)以及目标资源是什么(客户记录等),控制用户可以对给定记录执行什么操作

您需要做的是以松散耦合的方式在RESTAPI之上部署一个授权框架。换句话说,您希望将授权外部化。您肯定不想将授权直接构建到API中。想象一下,突然有了新的授权规则/约束:您必须重新编写API。这样做会破坏所有的客户。这将导致糟糕的用户体验

因此,我们已经确定您需要将授权外部化。伟大的有哪些不同的方法可以做到这一点?这取决于您使用的语言和框架

您可以使用:

  • Java中的Spring安全性
  • PHP中的Yii
  • 红宝石坎坎
  • 。。。还有更多
您还可以实现自己的过滤器,例如在REST端点前面的Java中的Servlet过滤器

最后,您可以转向基于XACML的全面的基于属性的授权模型。有几种开源和供应商替代方案。如果您不熟悉基于属性的访问控制或XACML,请查看以下链接:

使用XACML,您可以集中定义策略,例如:

  • 管理员可以查看所有客户帐户
  • 管理员可以修改分配给他的客户帐户
  • 客户只能查看和编辑自己的帐户
然后在授权服务中评估策略(在XACML中称为策略决策点)。授权服务公开一个二进制授权API,您的API可以调用该API:can user Alice view record foo


使用基于策略的外部化授权和XACML,您的业务逻辑(业务API)和授权逻辑之间实现了松散耦合,您可以更轻松地维护和更新这些逻辑。

根据我的理解,例如,您希望该客户仅查看其用户,而不能创建仅由管理员创建的用户,因此,这也可以使用Spring Security来完成,这肯定会产生问题,所以您必须根据您的需求对客户进行分类。考虑服务的3个角色:管理员、客户管理员和客户用户。管理员可以创建和查看任何内容。客户管理员可以创建其他用户