使用 Spring 检查实体/对象是不是属于当前登录的用户
Posted
技术标签:
【中文标题】使用 Spring 检查实体/对象是不是属于当前登录的用户【英文标题】:Checking whether or not entities/objects belong to the currently logged-in user with Spring使用 Spring 检查实体/对象是否属于当前登录的用户 【发布时间】:2014-04-22 15:55:08 【问题描述】:我正在开发一个 Spring Web 应用程序,它使用:
Spring MVC 弹簧芯 春袋鼠 Spring 安全性 Spring 数据 JPA mysql我遇到的问题如下:对于从 web 层到应用程序的实体/对象的每次访问我希望能够检查是否不是他们确实属于当前用户。
让我举例说明:应用程序的用户有广告、课程(称为实体/对象)。我经常使用 PK/ID 对这些对象/实体执行 GET 或 POST,以便检索、更新或删除这些对象。到目前为止,我还没有找到一种简洁灵活的方法来防止用户检索、更新或删除其他人的对象。
我使用 Spring Security 并且 我随时都知道谁是当前用户(当前登录的用户/主体),但我不确定在哪里(哪一层)以及如何执行检查。
我曾尝试使用 AspectJ 为服务和控制器方法提供建议,但我实现它的方式远非理想,因为仅更改方法签名会导致建议不被应用。
我可以将 ACL 与 Spring Security 一起使用,但它增加了不必要的复杂性:我只需要根据实体是否属于帐户/用户来授予或拒绝对实体的访问权限。
任何已经遇到此问题的人都可以提供一个干净、灵活且 DRY 的解决方案吗?
【问题讨论】:
【参考方案1】:在我看来,这是一个授权问题。本质上,您要确认当前用户具有对实体/对象执行操作的正确权限。因此,我建议您的解决方案应用于服务层(中间层)。
Spring Security 架构的很大一部分是处理授权决策。值得花时间阅读 section of the documentation 以确保您了解一般架构。
广义地说,Spring Security 将调用前访问决策委托给AccessDecisionManager
。 AccessDecisionManager
通常会查阅已注册的 AccessionDecisionVoter
s 列表,顾名思义,这些 AccessionDecisionVoter
s 会根据当前的执行状态“投票”是否允许调用继续进行,例如谁登录,用户请求什么数据。
AccessDecisionVoter
如何决定是否授予访问权限完全取决于实现。所以理论上你可以做任何事情来决定是否授权一个特定的请求。
谢天谢地(正如您所期望的那样)Spring 提供了一些相当合理的默认实现,可以让您开箱即用地实现很多您想要的东西。特别是我相信Method Security Expressions 应该可以让你实现你想要的(这将取决于你的服务是如何实现的)。
根据文档,您可以将 Spring Security 的 @PreAuthorise
注释与一些查看当前方法调用或执行上下文的参数的表达式结合使用。例如:
@PreAuthorise("#u == principal.id")
public List<Foo> loadFoos(@P("u")String userId);
在本例中,仅当userId
参数的值与当前经过身份验证的用户的 id 完全匹配时,才允许进行方法调用。
您的具体方法/表达方式将取决于您的服务是如何实现的,但希望这可以为您提供一个良好的起点。
【讨论】:
嗨,罗伯!您的回复非常有用,确实很有趣!请让我检查一下我的代码的某些方面,我会用其他 cmets 回复你... 首先想到的一点:官方文档似乎建议人们也可以将@PreAuthorize
注释放在存储库方法(而不是服务方法)上,我将 spring 数据与 spring 一起使用罗。存储库方法由 roo 自动生成,默认的 finder 方法不是“可见的”。然后如何将我的 @PreAuthorize
方法放在这些方法上?
不幸的是,我不知道答案。我以前从未使用过 Spring Roo,所以我不知道在自定义自动生成实现的行为方面从哪里开始。
不用担心。我添加了另一个与我上面的评论更相关的问题here。将此标记为已接受。
嗨,Rob,非常有用的信息。 @balteo,正如您添加的那样,在存储库方法(而不是服务方法)上预先授权注释,这可以限制对资源访问的资源的访问,如果在服务层执行授权会更加灵活,而不是从哪里开始数据被访问。因为,在某些情况下,服务可能会与 solr 和其他数据存储进行交互。以上是关于使用 Spring 检查实体/对象是不是属于当前登录的用户的主要内容,如果未能解决你的问题,请参考以下文章
即使 JPA 实体不脏,我是不是可以强制 spring-data 更新可审计字段?