如果我有一个实体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。该论文的结论表明,一种好方法是注释域对象方法以保护它们。有什么想法吗?
答案 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中的深度衰减。