保护敏感实体数据

发布于 2024-09-02 15:01:22 字数 977 浏览 2 评论 0原文

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

客户端是一个相当厚重的客户端,服务器主要负责持久性、并发性和基础设施问题。 服务器包含许多包含敏感信息和公共信息的实体。例如,假设实体是人,假设社会安全号码和姓名是敏感的,并且年龄是公开可见的。

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

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

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;
}

一些担忧:

  • 如果用户登录然后退出,敏感数据已加载但必须再次泄露怎么办?
  • 有人可能会争辩说,这种类型的功能属于域内,而不是某些基础设施实现(即存储库实现)。
  • 与往常一样,在处理大量属性时,存在此类功能使代码混乱的风险

任何见解或讨论都值得赞赏!

I'm looking for some advice on architecture for a client/server solution with some peculiarities.

The client is a fairly thick one, leaving the server mostly to peristence, concurrency and infrastructure concerns.
The server contains a number of entities which contain both sensitive and public information. Think for example that the entities are persons, assume that social security number and name are sensitive and age is publicly viewable.

When starting the client, the user is presented with a number of entities, not disclosing any sensitive information. At any time the user can choose to log in and authenticate against the server, given the authentication is successful the user is granted access to the sensitive information.

The client is hosting a domain model and I was thinking of implementing this as some kind of "lazy loading", making the first request instantiating the entities and later refreshing them with sensitive data. The entity getters would throw exceptions on sensitive information when they've not been disclosed, f.e.:

class PersonImpl : PersonEntity
{
    private bool undisclosed;

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

            return base.SocialSecurityNumber;
        }
    }
}

Another more friendly approach could be to have a value object indicating that the value is undisclosed.

get {
    if (undisclosed)
        return undisclosedValue;

    return base.SocialSecurityNumber;
}

Some concerns:

  • What if the user logs in and then out, the sensitive data has been loaded but must be disclosed once again.
  • One could argue that this type of functionality belongs within the domain and not some infrastructural implementation(i.e. repository implementations).
  • As always when dealing with a larger number of properties there's a risk that this type of functionality clutters the code

Any insights or discussion is appreciated!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

画尸师 2024-09-09 15:01:22

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

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

我的意见有几点:

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

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

但是,您可以使用类似于 AutoMapper 的东西(取决于您的平台)来帮助填充您的视图来自您的实体的模型。

I think that this is actually a great example of using View Models. Your concern seems directly related to the consumption of the entities, because of the data that they contain. Instead of passing your entities all the way up to the UI, you could restrict them to live within the domain only - i.e. no entities are passed into or out of the domain at all, with most/all activities done with a command/query approach on the repositories. Repositories would then return a view model instead of the entity.

So how/why does this apply? You could actually have two different view models. One for authenticated and one for non-authenticated users. You expose the actual values for the sensitive data in the authenticated view model and not for the non-authenticated one. You could have them derived from a common interface, and then code against the interface instead of the object type. For your concrete implementation of the non-authenticated user, you can just populate the non-sensitive data, leaving the sensitive getters to do what you want them to do.

My opinion on a couple of points:

  • I am not a fan of lazy loading in entities. Lazy loading is a data access responsibility and not really part of the model. For me, it is a first-class member of the things I vehemently avoid in my domain, along with paging and sorting. As for how to relate these items together, I would rather loosely couple the objects via ID pointers to other entities. If I want/need the data contained by one of these entities, then I can load it. It is kind of like lazy loading in a way, but I enforce that it never happens in the domain model itself by doing this.
  • I am not a fan of throwing exceptions on getters. Setters, on the other hand, is fine. I look at it this way. The entity should always be in a valid state. Getters will not impact the state of the entity - setters will. Throwing on a setter is enforcing the integrity of the model. Using the two view model approach would allow me to move the logic to the presenter. So, I could basically do something like "if user is of type non-authorized, do this; otherwise do something else". Since what you are referring to would ultimately be a case of how the data is presented to the user, and not important to the model, I think it fits well. In general, I use nullable types for my properties that can be null and do not enforce anything on the getters, as it is not part of its responsibility, usually. Instead, I use roles to determine what view model to use.

The obvious drawback is that there is more coding required to use the view models, but it comes at the obvious benefit of decoupling presentation and views from the domain. It also will help in unit/integration testing, where you can verify that a certain view model cannot return a type of data.

However, you can use something akin to AutoMapper (depending on what your platform is) to help in populating your view model from your entities.

天赋异禀 2024-09-09 15:01:22

我犯了一个错误,在没有创建 OpenId 的情况下发布了问题,所以看起来我必须在这里发表评论(?)。

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

因此,域层具有如下实体:

class Entity {
    virtual string SocialSecurityNumber { get; }
}

基础设施层添加了一些其他功能,以便能够从服务器更新和恢复实体:

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

因此,延迟加载行为将在基础设施层中实现,并且域层永远不会看到。

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

I made the mistake of posting the question without creating an OpenId so it looks like I'll have to comment here(?).

First of all, thanks for taking you time to answer - It certainly has more to do with how data is presented than how the model works. However, I feel the need to clarify a few things.
The domain model / entities are never referenced directly from the UI. I'm using a variant of the DM-V-VM pattern for UI/business model separation. For lazy loading and repository implementation in general I have entity implementations in a infrastructure layer where things like serialization, dirty tracking and lazy loading is handled.

So the domain layer has entities like:

class Entity {
    virtual string SocialSecurityNumber { get; }
}

And the infrastructure layer adds some other functionality to be able to update and restore entites from a server:

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

So the lazy loading behavior would be implemented in the infrastructure layer and never seen by the domain layer.

I agree that throwing on getters wouldn't be nice but my concerns are on how an anonymous view model would retrieve the data. As of now, to retrieve a list of entities the viewmodel would hold a reference to a domain repository, should I have two repositories, one for authenticated(and therefore disclosed) entities, and another one for the unauthenticated users - maybe even two different entities?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文