保护域对象的正确方法?

时间:2010-11-15 09:53:04

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

如果我有一个实体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?)

EDIT2

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

2 个答案:

答案 0 :(得分:2)

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

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

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

答案 1 :(得分:1)

如果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方法返回只读{{1 }})。

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