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 的结果。我不能使用preFilter
annotation,因为我需要考虑用户角色。我有三个不同的角色:
user
普通用户,只能访问自己拥有的数据
teamleader
这个角色应该访问他团队的所有数据
admin
可以访问所有数据。
因为我们的数据库结构非常复杂,所以在我决定用户是否可以访问请求的数据或请求的部分数据之前,有必要访问一些其他数据。
sn-p 仅适用于角色user
和admin
。对于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 调用中获取用户信息?