1

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

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

4

2 回答 2

2

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

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

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

于 2010-11-15T10:36:37.953 回答
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(); }
}

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

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

于 2010-11-18T06:58:13.883 回答