[英]Security questions on Spring Data JPA Rest (JpaRepository)
我正在(尝试:)在Spring Boot应用程序中使用spring-boot-starter-data-rest通过真实的,成熟的restFULL api快速提供模型服务。 效果很好。
问题1(安全性):
Spring JpaRepository的优点是我不需要编写基本功能(save,findAll等)。 是否有可能在不覆盖所有自动实现方法的情况下保护这些自动实现的方法(浪费了Spring为我提供的功能)? 即:
public interface BookRepository extends JpaRepository<Book, Long> {
@PreAuthorize("hasRole('ROLE_ADMIN')")
<S extends Book> Book save(Book book);
}
。
问题2(安全性):
如何保护JpaRepository以防止更新登录用户不是所有者的项目? 即:允许用户仅修改他/她自己的属性。 ie2:只允许用户修改/删除他/她创建的帖子。 这里非常欢迎示例代码。
。
问题3(DTO):
前一段时间,我和一个开发人员朋友发生了争执:他暗示必须从Spring MVC控制器返回DTO。 即使DTO是模型对象的1-1副本。 然后,我重新安排工作,问其他人并确认:DTO需要划分/隔离应用程序层。
这与JpaRepositories有何关系? 如何在Spring Auto Serverd Rest Repos中使用DTO? 我应该完全使用DTO吗?
感谢您的提前提示/回答!
问题1 :安全性
一些旧文档提到:
您向不受您控制的客户端公开了一组预定义的操作,直到现在几乎全部还是全部。 似乎没有办法只公开读取操作,而完全隐藏状态更改操作。
这意味着所有方法都是自动继承的(也按照标准的java
继承行为)。
根据@PreAuhtorize文档,您还可以将注释放置在类/接口声明上。
因此,您只需一个基本接口即可扩展JpaRepository
@NoRepositoryBean // tell Spring not create instances of this one
@PreAuthorize("hasRole('ROLE_ADMIN')") // all methods will inherit this behavior
interface BaseRepository<T, ID extends Serializable> extends Repository<T, ID> {}
然后使您的Repository
的所有扩展BaseRepository
。
问题2 :安全性
我将对此进行更概括的介绍。
为了正确地规范对应用程序中实体的访问并定义可以看到什么 ,您应该始终将项目分成不同的层。
一个好的起点是:
layer-web
(或表示层):访问layer-business
,不能访问db-layer
。 可以看到DTO
模型但看不到DB models
layer-business
(或业务层):访问db-layer
但不访问DAO
layer-db
(或data-layer):转换DTO -> DB model
。 持久化对象并提供查询结果 对于您而言,我认为正确的做法是在请求甚至到达Repository
类之前检查layer-business
的角色。
@Service
public interface BookService {
@PreAuthorize("hasRole('ROLE_ADMIN')")
ActionResult saveToDatabase(final BookDTO book);
}
或者,如前所述
@Service
@PreAuthorize("hasRole('ROLE_ADMIN')")
public interface BookService {
ActionResult saveToDatabase(final BookDTO book);
}
同样,确保用户只能修改其自己的对象可以通过多种方式来完成。
正如该答案所指出的那样, Spring
提供了所有必要的资源来做到这一点 。
或者,如果您熟悉AOP
,则可以实现自己的逻辑。
例如(dummyCode):
@Service
public interface BookService {
// custom annotation here
@RequireUserOwnership(allowAdmin = false)
ActionResult saveToDatabase(final BookDTO book);
}
和检查:
public class EnsureUserOwnershipInterceptor implements MethodInterceptor {
@Autowired
private AuthenticationService authenticationService;
@Override
public Object invoke(Invocation invocation) throws Throwable {
// 1. get the BookDTO argument from the invocation
// 2. get the current user from the auth service
// 3. ensure the owner ID and the current user ID match
// ...
}
}
问题3 : DTO
和DB models
我应该完全使用DTO吗?
是的,是的,你应该。 即使您的项目只有几个模型,并且您只是出于娱乐目的而编程(仅在localhost上部署,学习等)。
您越早养成分离模型的习惯,就越好。
同样,从概念上讲,一个是来自未知来源的对象,另一个是您数据库中的表。
这与JpaRepositories有何关系? 如何在Spring Auto Serverd Rest Repos中使用DTO?
这就是重点! 您不能将DTO
放入@Repository
。 您被迫将一个转换为另一个。 同时,您还必须验证转换是否有效。
基本上,您要确保DTO
(脏数据)不会以任何方式接触数据库,并且要在数据库和应用程序的其余部分之间放置一堵由逻辑约束构成的墙。
我也知道Spring
与模型转换框架很好地集成在一起。
那么, multi-layer
/ modular
Web应用程序的优点是什么?
应用程序可以快速增长。 尤其是当您有许多开发人员在工作时。 一些开发人员倾向于寻找最快的解决方案并实施肮脏的技巧或更改访问修饰符以尽快完成工作。 您应该强迫人们仅通过某些明确定义的渠道来访问某些资源。 从一开始设置的规则越多,遵循正确编程模式的时间就越长。 不到一年的时间,我已经看到银行申请变得一团糟。 当需要hotfix
时,更改某些代码将创建另外两个bug 。
您可能会达到应用程序占用过多OS资源的地步。 假设您有一个包含您的应用程序后台作业的模块module-batch
,则将其提取并将其实现到另一个应用程序中会更加容易。 如果您的模块包含查询数据库,访问任何类型的数据,为前端提供API的逻辑等等,那么您将基本上被迫将所有代码导出到新应用程序中。 重构在那时将是脖子上的痛苦。
假设您想聘请一些数据库专家来分析您的应用程序执行的查询。 使用定义明确且分离的逻辑,您可以使他们仅访问必要的modules
而不是整个应用程序。 同样适用于前端自由职业者等。我也经历过这种情况。 该公司希望数据库专家修复应用程序完成的查询,但不希望他们可以访问整个代码。 最后,他们放弃了数据库优化,因为那样会使外部暴露太多敏感信息。
DTO
/ DB model
分离的优点是什么?
DTO
不会接触数据库。 这为您提供了更高的安全性,可抵御来自外部的攻击 DTO
不需要将所有字段都实现为db模型。 实际上,您甚至可以将DAO
映射到许多DTO
或相反。 有很多信息不应该到达前端,而使用DTO
可以轻松地做到这一点。 DTO
通常比@Entity
模型更@Entity
。 实体被映射(例如@OneToMany
)到其他实体,而DTO
可能仅包含映射对象的id字段。 我个人认为,任何有礼貌的Web应用程序都应将各个层严格分开,每个层都有其责任,并且对其他层的可见性有限。
数据库模型与数据传输对象之间的区别也是遵循的好模式。
最后,这只是我的意见 ; 许多人认为DTO
模式已经过时并导致不必要的代码重复,许多人则认为,过多的分离倾向于难以维护代码。 因此,您应该始终咨询不同的来源,然后应用最适合您的方法。
也很有趣:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.