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

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

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

[Organization Role ]     [Organization ID]
 CEO                        org01
   Financial Assistant      org0101
           personnel 1

   Software Assistant       org0102
           personnel 2

   Commercial Assistant     org0103
           personnel 3

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

[Organization]
id
code
name

[Employee]
id
first_name
last_name
organization_id

[User]
id
user_name
password

[UserOrganization]
user_id
organization_id

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

select *

from employee e 

where e.organization_id in

(select uo.organization_id

 from user_organization uo

 where uo.user_id=:authenticatedUserId)

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

e.organization_id in

(select uo.organization_id

 from user_organization uo

 where uo.user_id=:authenticatedUserId)

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

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

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

uemypmqf

uemypmqf1#

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

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

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

bcs8qyzn

bcs8qyzn2#

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

interface SecureBusinessObjectRepository extends Repository<BusinessObject, Long> {

    @Query("select o from BusinessObject o where o.owner.emailAddress like ?#{hasRole('ROLE_ADMIN') ? '%' : principal.emailAddress}")
    List<BusinessObject> findBusinessObjectsForCurrentUser();
}

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

@Service
public class UserService {
    public boolean checkAccess(Authentication authentication, int id) {
        // ...
    }
}

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    // ...

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/businessObjects/{id}/**").access("@userService.checkAccess(authentication, #id)")
            // ...
    }
}

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

相关问题