Spring Boot:考虑到用户角色,如何编写自定义 Pre Filter?

Posted

技术标签:

【中文标题】Spring Boot:考虑到用户角色,如何编写自定义 Pre Filter?【英文标题】:Spring Boot: Who to write a custom Prefilter, considering the user role? 【发布时间】:2019-03-13 05:39:53 【问题描述】:

我需要某种@preFilter(或者,如果不可能,则比@postFilter)来过滤我的REST API 的结果。我不能使用preFilterannotation,因为我需要考虑用户角色。我有三个不同的角色:

user 普通用户,只能访问自己拥有的数据

teamleader这个角色应该访问他团队的所有数据

admin 可以访问所有数据。

因为我们的数据库结构非常复杂,所以在我决定用户是否可以访问请求的数据或请求的部分数据之前,有必要访问一些其他数据。

sn-p 仅适用于角色useradmin。对于teamleader来说会更复杂,然后会有一堆masterDataId必须和or连接。

这是一些伪代码,希望它不会混淆:

public class RoleFilter 

    DimensionAttributeValueRepository dimensionAttributeValueRepository;


    public void doFilter(Collection<AllDatas> data) 
        if (user.getRole() != "admin") 
            Authentication auth = SecurityContextHolder.getContext().getAuthentication();

            DimensionAttributeValue tmpValue = dimensionAttributeValueRepository.findByChrValue(auth.getUsername());

            MasterData masterData = tmpValue.getMasterData();

            data.filter(data.masterDataId == masterData.getMasterDataID());
        
    


更新:示例

假设我有两个用户,用户 A 是角色“用户”的普通用户。用户 B 是具有“admin”角色的管理员。

有一个数据库表,其中存储了userData。该表如下所示。

| ID | username | name | email |

他们都向/userData发送了一个简单的认证GET请求。

现在我的后端根据authentication 标头检测用户并添加角色。

根据角色,用户 A 应该只得到一个包含他的个人数据的答案,用户 B 应该得到所有可以通过/userData 访问的数据。

用户 A 的响应:


   "res":[
      
         "id":1,
         "username":"userA",
         "name":"A",
         "email":"userA@mail.com"
      
   ]

用户 B 的响应:


   "res":[
      
         "id":1,
         "username":"userA",
         "name":"A",
         "email":"userA@mail.com"
      ,
      
         "id":2,
         "username":"userB",
         "name":"B",
         "email":"userB@mail.com"
      ,
      
         "id":3,
         "username":"userC",
         "name":"C",
         "email":"userC@mail.com"
      
   ]

【问题讨论】:

【参考方案1】:

对于您的用例,我建议使用自定义过滤器并将其集成到 spring-security 过滤器链中。 Here 是一个教程,一般性地解释它。您可以配置自定义过滤器,以便它根据数据库检查您的复杂角色,然后用新的身份验证对象覆盖当前用户身份验证对象。

示例实现:

public class CustomFilter extends GenericFilterBean 

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
    throws IOException, ServletException 
            // HERE GOES YOUR CODE

            // Depending on the extracted authentication details of the current user, you can now overwrite the users GrantedAuthorities

            Collection<SimpleGrantedAuthority> oldAuthorities = (Collection<SimpleGrantedAuthority>)SecurityContextHolder.getContext().getAuthentication().getAuthorities();
            SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_TEAMLEADER");
            List<SimpleGrantedAuthority> updatedAuthorities = new ArrayList<SimpleGrantedAuthority>();
            updatedAuthorities.add(authority);
            updatedAuthorities.addAll(oldAuthorities);

            SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(     
                SecurityContextHolder.getContext().getAuthentication().getPrincipal(),      
                SecurityContextHolder.getContext().getAuthentication().getCredentials(),
                updatedAuthorities));

            chain.doFilter(request, response);
    

之后,您可以使用以下语句检查您的角色:@PreAuthorize("hasRole('ROLE_TEAMLEADER')")

然后您可以在spring-security-context 对象的帮助下访问用户角色:SecurityContextHolder.getContext().getAuthentication().getAuthorities()

根据其结果,您现在可以根据存储在此对象中的角色自定义您的答案。例如,您可以像这样在 /userData 上实现 RestCall:

@GetMapping("/userData")
public List<Object> getUserData() 
  List<SimpleGrantedAuthority> roles = (List<SimpleGrantedAuthority>) SecurityContextHolder.getContext().getAuthentication().getAuthorities();
  SimpleGrantedAuthority authorityTeamLeader = new SimpleGrantedAuthority("ROLE_TEAMLEADER");

  List<Object> result = new ArrayList<>();

  if (roles.contains(authorityTeamLeader)) 
    result = getAllUsers();
   else 
    result = getPersonalUser(roles);
  

  return result;

【讨论】:

您好,感谢您的回答。但是,如果我对您的理解正确,这不会解决我的问题。我知道用户角色,问题是,我喜欢根据角色返回一组不同的数据。 更新了我的答案:) 再次感谢,但仍无法找到解决方案。让我再澄清一下这个问题。我有那个用户角色,我也实现了类似的东西,比如你的代码确实检查了哪种用户发送了请求。我将用一个例子更新我的原始帖子。感谢您尝试帮助我! 我已经添加了示例 我添加了另一个自定义 Get-Controller 的示例实现

以上是关于Spring Boot:考虑到用户角色,如何编写自定义 Pre Filter?的主要内容,如果未能解决你的问题,请参考以下文章

Spring-boot 安全性不会尊重具有自定义 AuthenticationProvider 的角色 [重复]

如何在 Spring Boot 中使用 Thymeleaf 保存角色?

使用 Spring Security 更新角色时如何注销用户

如何在 Spring-Boot-REST 调用中获取用户信息?

如何在不重启 Spring Boot 的情况下使用 Spring Security 添加新用户

如何从 Spring Boot REST Controller 获取角度视图中的用户 ID