spring-security 如何在Spring Data jpa中使用Hibernate过滤器或其他方法实现行级安全性?

c9qzyr3d  于 2022-11-11  发布在  Spring
关注(0)|答案(2)|浏览(210)

信息软件中一个非常重要的问题是存在不同角色的用户,这些用户具有不同的职责和访问级别。例如,设想一个组织的结构(层次结构)如下:

  1. [Organization Role ] [Organization ID]
  2. CEO org01
  3. Financial Assistant org0101
  4. personnel 1
  5. Software Assistant org0102
  6. personnel 2
  7. Commercial Assistant org0103
  8. personnel 3

假设该组织有一个管理人员信息的系统,该系统中人员信息展现的规则是:每个用户都可以看到自己有权访问的组织的人员信息;例如:user 1有“财务助理”和“商务助理”两个级别的权限,所以只能看到“人员1”和“人员3”的信息,user 2也有“商务助理”级别的权限,所以只能看到“人员3”的信息,所以这个系统中的每个用户都有一个特定的权限级别,现在考虑在这个系统中:每个用户登录后只能看到自己有权访问的人员信息,因此本系统的表结构如下:

  1. [Organization]
  2. id
  3. code
  4. name
  5. [Employee]
  6. id
  7. first_name
  8. last_name
  9. organization_id
  10. [User]
  11. id
  12. user_name
  13. password
  14. [UserOrganization]
  15. user_id
  16. organization_id

下面的查询将足以为每个用户获得正确的个人信息结果:

  1. select *
  2. from employee e
  3. where e.organization_id in
  4. (select uo.organization_id
  5. from user_organization uo
  6. where uo.user_id=:authenticatedUserId)

正如我们所看到的,下面的条件定义了用于显示正确数据的访问逻辑:

  1. e.organization_id in
  2. (select uo.organization_id
  3. from user_organization uo
  4. where uo.user_id=:authenticatedUserId)

这种访问级别也称为“行级安全性”另一方面,相应的存储库类可能有几个方法负责阅读数据,在这种情况下,访问级别条件将在某些地方重复(方法)。看起来使用'hibfilter'将是这个问题的一个适当的解决方案。唯一需要的是一个过滤器,它获取经过身份验证的用户的id,并在每个读取方法之前执行'enablefilter'命令。

  1. @Filters( {
  2. @Filter(name=“EmployeeAuthorize", condition="(organization_id in (select uo.organization_id from user_organization uo where uo.user_id=:authenticatedUserId) ) ")
  3. } )

现在的问题是,提出的解决方案是正确的吗?如果是,这种方法如何在Spring Data 中使用?PS:如果我们不想依赖于数据库,那么数据库端的实现就不是候选解决方案,因此我们必须在应用程序端(级别)实现它。

uemypmqf

uemypmqf1#

阿里,这是个有趣的场景.
这里有两个问题您需要回答。

第一个问题-公开数据时,系统只会进行筛选,还是您会执行其他操作?例如,如果您公开类似 users/{id} 的操作,则需要检查授权,并确保用户有权访问该操作。如果您只是公开类似 /users 的操作,则只需进行筛选即可。因为您将只公开当前用户有权查看的用户,这种区别将决定很多实现。
第二个问题是-您可以接受多少手动工作?

一方面,您可以根据框架的需要调整数据,并尽可能依赖于内置功能(安全表达式、ACL);另一方面,您可以根据数据的结构调整代码,并更多地手动执行操作。
这是我首先关注的两个因素,因为基于这四个决定,实施将看起来完全不同。
最后,要回答您的“ACL是否可以扩展”问题,请注意两点。第一,您需要进行测试。是的,ACL可以扩展,但如果不进行测试,它是否可以扩展到10 K或100 K,这是一个无法具体回答的问题。
第二,当你进行测试时,考虑现实的场景。理解你的解决方案的局限性当然很重要。但是,除此之外,如果你认为你的系统会有100万个实体--很好。但是如果它不会--那么就不要把它作为一个目标。
希望能有所帮助。

bcs8qyzn

bcs8qyzn2#

使用Spring,您可以使用以下内容:
1)您可以使用SpEL EvaluationContext扩展,使安全属性和表达式在@Query注解的SpEL表达式中可用。这允许您仅获取与当前用户相关的业务对象:

  1. interface SecureBusinessObjectRepository extends Repository<BusinessObject, Long> {
  2. @Query("select o from BusinessObject o where o.owner.emailAddress like ?#{hasRole('ROLE_ADMIN') ? '%' : principal.emailAddress}")
  3. List<BusinessObject> findBusinessObjectsForCurrentUser();
  4. }

2)您可以参照Bean并在Web安全表示式中使用路径变数。这可让您只授与目前使用者可以存取的对象:

  1. @Service
  2. public class UserService {
  3. public boolean checkAccess(Authentication authentication, int id) {
  4. // ...
  5. }
  6. }
  7. @Configuration
  8. @EnableWebSecurity
  9. public class SecurityConfig extends WebSecurityConfigurerAdapter {
  10. // ...
  11. @Override
  12. protected void configure(HttpSecurity http) throws Exception {
  13. http.authorizeRequests()
  14. .antMatchers("/businessObjects/{id}/**").access("@userService.checkAccess(authentication, #id)")
  15. // ...
  16. }
  17. }

检查my demo project以了解更多详细信息。在本例中,如果用户属于与这些用户相关的类别,则用户可以访问工作室。管理员可以访问所有工作室。

展开查看全部

相关问题