我正在实现一个 RESTful 服务,该服务具有需要在三个级别进行授权的安全模型:
访问资源(实体)。例如,是否
当前用户一般有权查看客户。如果不,
然后一切都停在那里。
访问资源(实体)的特定实例。由于
各种规则和实体的状态,当前用户可能不会
被授予访问一组中的多个客户之一的权限
客户。例如,客户可能能够查看自己的信息,但不能查看其他客户的信息。
可以访问资源(实体)的实例。我们有很多
确定用户是否可以看到和/或更改的业务规则
资源(实体)的各个属性。例如,
当前用户可能能够看到客户的姓名,但看不到他们的
地址或电话号码以及能够查看和添加注释。
实现资源级授权很简单;然而,另外两个不是。我相信实例级授权的解决方案将通过解决(更难的,imo)属性(property)级授权问题来揭示自己。由于我需要在响应消息(ala 超媒体)中按属性传达授权决定,后一个问题变得复杂 - 换句话说,这不是我可以简单地在属性 setter 中强制执行的内容。
对于对服务的每个请求,我必须使用当前用户的信息来执行这些授权检查。在对资源列表或单个资源的 GET 请求的情况下,我需要告诉 API 层当前用户可以看到(可见)哪些属性以及该属性是只读还是可编辑。 API 层随后将使用此信息来创建适当的响应消息。例如,任何不可见的属性都不会包含在消息中。只读属性将被标记,以便客户端应用程序可以为用户以适当的状态呈现属性。
应用程序服务、方面等解决方案非常适用于资源级授权,甚至可以用于实例级检查,但我无法确定如何最好地为我的域建模,以便包括实现安全约束的业务规则和检查.
注意:请记住,这超出了基于角色的安全性,因为我使用资源和环境的当前状态根据业务规则获得最终授权结果(以及使用授予当前用户的权限验证访问)他们的角色)。
我应该如何对域建模,以便强制执行所有三种类型的授权检查 (以可测试的方式,使用 DI 等)?
最佳答案
初始假设
我假设以下架构:
Stateless Scaling Sharding
. .
. .
. .
+=========================================+
| Service Layer |
+----------+ | +-----------+ +---------------+ | +------------+
| | HTTP | | | | | | Driver, Wire, etc. | |
| Client | <============> | RESTful | <====> | Data Access | <=======================> | Database |
| | JSON | | Service | DTO | Layer | | ORM, Raw, etc. | |
| | | | | | | | | |
+----------+ | +-----------+ +---------------+ | +------------+
+=========================================+
. .
. .
. .
最初,让我们假设您正在验证
Client
与 Service Layer
并获得一个特定的 token ,该 token 对其中的身份验证和授权信息进行编码。首先,我首先想到的是处理所有请求,然后仅根据授权对其进行过滤。这将使整个事情变得更简单,更容易维护。但是,当然可能有一些请求需要昂贵的处理,在这种情况下,这种方法绝对无效。另一方面,重负载请求很可能涉及资源级别的访问,正如您所说的那样易于组织,并且可以在
Service Layer
中检测和授权。在 API
或至少 Data Access
水平。进一步思考
至于例如和属性(property)级别的授权,我什至不会尝试将其放入
Data Access Layer
并将其完全隔离在 API 级别之外,即从 Data Access Layer
开始没有任何层甚至会意识到它。即使您请求一个包含 1M 个对象的列表并希望从该特定客户端的所有对象中发出一两个属性,也最好获取整个对象,然后仅隐藏这些属性。另一个假设是您的模型是清晰的
DTO
,即简单的一个数据容器,所有的业务逻辑都在Service Layer
中实现,特别是 API
水平。假设您通过编码为 JSON
的 HTTP 传递数据.所以无论如何,在 API
前面的某个地方层,您将有一个小的序列化阶段,将您的模型转换为 JSON
.所以这个阶段是我认为放置实例和属性授权的理想场所。建议
如果涉及到属性级别的授权,我认为没有合理的方法可以将模型与安全逻辑隔离。无论是基于规则、基于角色或基于任何方式的授权,该过程都将根据
Client
提供的身份验证/授权 token 中的一个值进行验证。 .因此,在序列化级别,您基本上将获得两个参数, token 和模型,并相应地将适当的属性或实例作为一个整体进行序列化。当涉及为模型定义规则、角色和每个属性的任何内容时,可以根据可用范例以各种方式完成,即取决于
Service Layer
的语言。将实现。可以大量使用 Annotations (Java) 来完成定义。或 Decorators (Python) .为了发出特定的属性,Python 将凭借其动态类型和 hacky 功能派上用场,例如Descriptors .在 Java 的情况下,您可能最终将属性封装到模板类中,例如 AuthField<T>
.摘要
综上所述,我建议将实例和属性授权放在
API Layer
前面。在序列化阶段。因此,基本上,角色/规则将在模型中分配,授权将在序列化器中执行,提供模型和 token 。
关于security - 在域对象中强制执行属性级授权,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30002351/