保护敏感的实体数据

时间:2010-05-18 09:20:52

标签: domain-driven-design client-server lazy-loading thick-client

我正在寻找有关具有一些特性的客户端/服务器解决方案的架构建议。

客户端相当厚,使服务器主要处于持久性,并发性和基础架构问题。 服务器包含许多包含敏感信息和公共信息的实体。例如,假设实体是人,假设社会安全号码和名称是敏感的,年龄是公众可见的。

启动客户端时,会向用户显示许多实体,而不会泄露任何敏感信息。用户可以随时选择登录并对服务器进行身份验证,如果身份验证成功,则授予用户访问敏感信息的权限。

客户端正在托管域模型,我正在考虑将其实现为某种“延迟加载”,使第一个请求实例化实体,然后使用敏感数据刷新它们。实体获取者在敏感信息未被披露时会抛出异常,例如:

class PersonImpl : PersonEntity
{
    private bool undisclosed;

    public override string SocialSecurityNumber {
        get {
            if (undisclosed)
                throw new UndisclosedDataException();

            return base.SocialSecurityNumber;
        }
    }
}

另一种更友好的方法可能是让值对象指示该值未公开。

get {
    if (undisclosed)
        return undisclosedValue;

    return base.SocialSecurityNumber;
}

一些担忧:

  • 如果用户登录然后退出,敏感数据已加载但必须再次披露。
  • 有人可能会说这种类型的功能属于域内而不是某些基础结构实现(即存储库实现)。
  • 与处理大量属性一样,这种类型的功能可能会使代码混乱

非常感谢任何见解或讨论!

2 个答案:

答案 0 :(得分:2)

我认为这实际上是使用View Models的一个很好的例子。您的关注似乎与实体的消耗直接相关,因为它们包含的数据。您可以将它们限制为仅在域内生存,而不是将实体限制在域内 - 即根本不会将任何实体传入或传出域,而大多数/所有活动都使用命令/查询方法完成,而不是将您的实体一直传递到UI。在存储库上。然后,存储库将返回视图模型而不是实体。

那么如何/为何适用?你实际上可以有两种不同的视图模型。一个用于认证用户,一个用于未经认证的用户。您在经过身份验证的视图模型中公开了敏感数据的实际值,而不是在未经过身份验证的模型中公开。您可以从公共接口派生它们,然后针对接口而不是对象类型进行编码。对于未经身份验证的用户的具体实现,您可以只填充非敏感数据,让敏感的getter执行您希望他们执行的操作。

我的意见有几点:

  • 我不是实体中延迟加载的粉丝。延迟加载是数据访问的责任,而不是模型的一部分。对我来说,它是我在我的领域中强烈避免的事情的一流成员,以及分页和排序。至于如何将这些项目联系在一起,我宁愿通过ID指针将对象松散地耦合到其他实体。如果我想/需要其中一个实体包含的数据,那么我可以加载它。它有点像延迟加载在某种程度上,但我强制执行它从未发生在域模型本身这样做。
  • 我不喜欢在getter上抛出异常。另一方面,塞特斯很好。我是这样看的。实体应始终处于有效状态。 Getters不会影响实体的状态 - setters会。投掷一个setter是强制模型的完整性。使用两种视图模型方法将允许我将逻辑移动到演示者。所以,我基本上可以做一些事情,比如“如果用户是非授权类型,请执行此操作;否则执行其他操作”。由于您所指的最终将是数据如何呈现给用户的情况,并且对模型不重要,我认为它非常适合。一般来说,我为我的属性使用可空类型,这些类型可以为null,并且不对getter强制执行任何操作,因为它通常不是其职责的一部分。相反,我使用角色来确定要使用的视图模型。

明显的缺点是使用视图模型需要更多编码,但它具有将表示和视图与域分离的明显好处。它还有助于单元/集成测试,您可以在其中验证某个视图模型无法返回某种类型的数据。

但是,您可以使用类似于AutoMapper的内容(取决于您的平台),以帮助您从实体中填充视图模型。

答案 1 :(得分:0)

我错误地发布了问题而没有创建OpenId,所以看起来我必须在这里发表评论(?)。

首先,感谢您抽出时间回答 - 这肯定与数据的呈现方式有关,而不是模型的工作方式。但是,我觉得有必要澄清一些事情。 域模型/实体永远不会直接从UI引用。我正在使用DM-V-VM模式的变体进行UI /业务模型分离。对于延迟加载和存储库实现,我在基础结构层中有实体实现,其中处理序列化,脏跟踪和延迟加载等事情。

因此,域图层具有以下实体:

class Entity {
    virtual string SocialSecurityNumber { get; }
}

基础架构层添加了一些其他功能,以便能够从服务器更新和恢复entites:

class EntityImpl : Entity {
    bool isDirty;
    bool isLoaded;
    // Provide the means to set value on deserialization
    override string SocialSecurityNumber;
}

因此,延迟加载行为将在基础架构层中实现,并且从未被域层看到。

我同意抛弃getter并不好,但我关注的是匿名视图模型如何检索数据。截至目前,要检索视图模型将保存对域存储库的引用的实体列表,我应该有两个存储库,一个用于经过身份验证(因此已公开)的实体,另一个用于未经身份验证的用户 - 甚至可能是两个不同的实体?