【问题标题】:Proper way to secure domain objects?保护域对象的正确方法?
【发布时间】:2010-11-15 09:53:03
【问题描述】:

如果我有一个实体 Entity 和一个服务 EntityService 和 EntityServiceFacade 具有以下接口:

interface EntityService {

 Entity getEntity(Long id);

}

interface EntityServiceFacade {

 EntityDTO getEntity(Long id);

}

通过在服务级别控制对 getEntity 方法的访问,我可以轻松地保护对实体的读取访问。但是一旦门面引用了一个实体,我该如何控制对它的写访问呢?如果我有一个 saveEntity 方法并像这样在服务(而不是外观)级别控制访问(此处使用 Spring 安全注释):

class EntityServiceImpl implements EntityService {

 ...

 @PreAuthorize("hasPermission(#entity, 'write')")
 public void saveEntity(Entity entity) {

  repository.store(entity);
 }

}

class EntityServiceFacadeImpl implements EntityServiceFacade {

 ...

 @Transactional
 public void saveEntity(EntityDTO dto) {

  Entity entity = service.getEntity(dto.id);
  entity.setName(dto.name);
  service.save(entity);
 }

}

这里的问题是访问控制检查在我更改实体名称之后已经发生,所以这还不够。

你们是怎么做到的?您是否改为保护域对象方法?

谢谢

编辑:

如果您保护您的域对象,例如使用以下注释:

@PreAuthorize("hasPermission(this, 'write')")
public void setName(String name) { this.name = name; }

然后我是否打破了域模型(根据 DDD?)

编辑2

我在该主题上找到了thesis。该论文的结论说,一个好的方法是注释域对象方法以保护它们。对此有什么想法吗?

【问题讨论】:

    标签: security spring domain-driven-design spring-security code-access-security


    【解决方案1】:

    我不会担心保护单个实体方法或属性不被修改。

    如果您可以控制持久性,则并不总是需要阻止用户更改内存中的实体。

    这里最大的问题是用户体验,您希望尽早通知用户她可能无法持久保存对该实体所做的更改。您需要做出的决定是是否可以将安全检查延迟到持久化时间,或者您是否需要提前通知用户(例如通过停用 UI 元素)。

    【讨论】:

    • 我知道如果我这样做了,那么我最终必须执行像 entityApplicationService.save(entity) { repository.store(entity) } 这样的空方法来控制访问。因此,如果我不保护域对象本身,它似乎对我做一个丰富的域模型没有帮助?
    【解决方案2】:

    如果Entity 是一个接口,你就不能直接膜它吗?

    所以如果实体看起来像这样:

    interface Entity {
      int getFoo();
      void setFoo(int newFoo);
    }
    

    创建一个类似的膜

    final class ReadOnlyEntity implements Entity {
      private final Entity underlying;
    
      ReadOnlyEntity(Entity underlying) { this.underlying = underlying; }
    
      public int getFoo() { return underlying.getFoo(); }  // Read methods work
    
      // But deny mutators.
      public void setFoo(int newFoo) { throw new UnsupportedOperationException(); }
    }
    

    如果您注释读取方法,您可以使用代理类来自动创建跨多个类的膜(这样,在只读Entity 上返回EntityPart 的get 方法返回只读EntityPart)。

    有关此方法的更多详细信息,请参阅http://en.wikipedia.org/wiki/Object-capability_model 中的深度衰减。

    【讨论】:

      猜你喜欢
      • 2015-10-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-07
      • 1970-01-01
      相关资源
      最近更新 更多