在春季安全中实施大量级联角色和当局的更好方法?

发布于 2025-02-11 19:33:18 字数 1853 浏览 1 评论 0原文

因此,我目前正在重构后端代码,以供我的组织准备以后的升级。它目前运行良好,只是因为该组织中存在的角色和授权庞大,因此代码变得非常凌乱。

因此,我们的后端堆栈是一个简单的Springboot REST API,我们使用第三方OAuth身份验证提供商作为我们的安全提供商。

因此,对于每一个进来的请求,我们都有一个弹簧安全过滤器,该过滤器可以从身份验证标题JWT中获取用户角色,并基于此分配授权。

    List<GrantedAuthority> authorities = new ArrayList<>();
    for (Map.Entry<String,Object> role : user.getCustomClaims().entrySet()) {
        authorities.add(new SimpleGrantedAuthority((String) user.getCustomClaims().get("role")));
    }
    SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(user.getEmail(), user.getUid(), authorities));
    filterChain.doFilter(request, response);

现在,由于存在的角色和身份验证的数量而存在,因此存在“问题”,当该公司首次成为8年前的公司时,该公司是一家简单的初创公司,有10名员工,现在是一家中型公司,拥有500〜员工。因此,角色和当局的数量呈指数增长。

例如,对于财务部门,我们目前有5个级别的权力,它们都彼此级联。

  • 金融头
  • 金融管理
  • 金融3
  • 财务2
  • 融资1

其中,金融管理员拥有财务3 +其自己的独家权限等所有权限。

而REST API中的每个端点最终都看起来像这样:

@PreAuthorize("hasAuthority('FinanceHead') or hasAuthority('FinanceAdmin') or hasAuthority('Finance3') or hasAuthority('Finance2') or hasAuthority('Finance1')")

许多端点具有20多个范围的多部门。不要误会我的意思,这当前效果很好,但是改变一个角色的痛苦是因为ID必须搜索所有终点并更改每个终点。有更好的方法吗?

我当时有可能将GrantedAuthority对象覆盖为这样的东西:

public class GrantedAuthority {
    String role; ("Finance","Logistics", etc)
    int authLevel; (1,2,3,4,5)
}

对于每个主要端点,我可以做hasrole(“财务”),然后使用 在任何进一步的终点中,每种方法的Hasauth(&gt; 3),类似的事情:

@PreAuthorize("hasRole('Finance')
@CrossOrigin
@RestController
@RequestMapping("/test")
public class test {

@PreAuthorize("hasAuthority('authLevel > 3')
@GetMapping
    public ResponseEntity<String> ping() {
        return new ResponseEntity<>("test", HttpStatus.OK);
    }
}

有更好的方法可以做到这一点吗?

So i'm currently refactoring the backend code for my organization to prep for future upgrades. It currently runs fine, its just that the code is getting quite messy because of the sheer amount of roles and authorizations that exist in this org.

So our backend stack here is a simple springboot Rest API, we use a third party Oauth authentication provider as our security provider.

So for every request that comes in, we have a spring security filter that gets the users roles from the authenthication header JWT and assigns authorizations based on that.

    List<GrantedAuthority> authorities = new ArrayList<>();
    for (Map.Entry<String,Object> role : user.getCustomClaims().entrySet()) {
        authorities.add(new SimpleGrantedAuthority((String) user.getCustomClaims().get("role")));
    }
    SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(user.getEmail(), user.getUid(), authorities));
    filterChain.doFilter(request, response);

Now the "problem" exists because of the number of roles and authenthications that exist, when this was first made the company was a simple startup 8 years ago with 10 employees, now it's a middle sized company with 500~ employees. So the number of roles and authorities has grown exponentially.

For example just for the finance department, we currently have 5 levels of authority, and they all cascade one another.

  • Finance Head
  • Finance Admin
  • Finance 3
  • Finance 2
  • Finance 1

Wherein Finance Admin has all the permissions of Finance 3 + its own exclusive permissions and so on.

And each endpoint in the rest API end up looking like this:

@PreAuthorize("hasAuthority('FinanceHead') or hasAuthority('FinanceAdmin') or hasAuthority('Finance3') or hasAuthority('Finance2') or hasAuthority('Finance1')")

with many endpoints that are multi-department having 20+ hasAuthorities. Dont get me wrong this currently works fine, but its becoming a pain to change one role as then id have to search all endpoints and change each one. Is there a better way to do this?

I was thingking it might be possible to Override the GrantedAuthority object into something like this:

public class GrantedAuthority {
    String role; ("Finance","Logistics", etc)
    int authLevel; (1,2,3,4,5)
}

That way i can do hasRole("Finance") at for each main endpoint and then use
hasAuth(>3) for each method in in any further endpoints, something like this:

@PreAuthorize("hasRole('Finance')
@CrossOrigin
@RestController
@RequestMapping("/test")
public class test {

@PreAuthorize("hasAuthority('authLevel > 3')
@GetMapping
    public ResponseEntity<String> ping() {
        return new ResponseEntity<>("test", HttpStatus.OK);
    }
}

Is there a better way to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

不知所踪 2025-02-18 19:33:19

这就是我最终要做的事情,这要归功于Deinum M. Deinum向我展示了春季安全中存在等级角色。

因此,我所做的就是这样创建角色hiechies这样:

@Bean
    public RoleHierarchyImpl roleHierarchy() {
        RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
        roleHierarchy.setHierarchy(
                "ROLE_BOSS > ROLE_FINANCE_HEAD > ROLE_FINANCE_ADMIN > ROLE_FINANCE_3 > ROLE_FINANCE_2 > ROLE_FINANCE_1" 
        return roleHierarchy;
    }

private SecurityExpressionHandler<FilterInvocation> webExpressionHandler() {
        DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler();
        defaultWebSecurityExpressionHandler.setRoleHierarchy(roleHierarchy());
        return defaultWebSecurityExpressionHandler;
    }

然后将它们添加到我的安全配置中:

http                   
    .authorizeRequests().anyRequest().authenticated()
    .expressionHandler(webExpressionHandler())

所以现在

   @PreAuthorize("hasAuthority('FinanceHead') or hasAuthority('FinanceAdmin') or hasAuthority('Finance3') or hasAuthority('Finance2') or hasAuthority('Finance1')")
   @GetMapping("/test")
    public ResponseEntity<String> test1() {
        return new ResponseEntity<>("Test", HttpStatus.OK);
    }

我可以简单地去

@PreAuthorize("hasRole('ROLE_ADMIN_3')")
@GetMapping("/test")
public ResponseEntity<String> test1() {
    return new ResponseEntity<>("Test", HttpStatus.OK);
}

,如果请求具有以下任何角色:

ROLE_BOSS, ROLE_FINANCE_HEAD, ROLE_FINANCE_ADMIN, ROLE_FINANCE_3 

请求完成请求,else a 403被扔了。

Here's how I ended up going about this, thanks to M. Deinum for showing me that Hierarchial Roles exist in spring security.

So what I did was create Role Hiearchies like so:

@Bean
    public RoleHierarchyImpl roleHierarchy() {
        RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
        roleHierarchy.setHierarchy(
                "ROLE_BOSS > ROLE_FINANCE_HEAD > ROLE_FINANCE_ADMIN > ROLE_FINANCE_3 > ROLE_FINANCE_2 > ROLE_FINANCE_1" 
        return roleHierarchy;
    }

private SecurityExpressionHandler<FilterInvocation> webExpressionHandler() {
        DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler();
        defaultWebSecurityExpressionHandler.setRoleHierarchy(roleHierarchy());
        return defaultWebSecurityExpressionHandler;
    }

and then add them to my security configuration like so:

http                   
    .authorizeRequests().anyRequest().authenticated()
    .expressionHandler(webExpressionHandler())

so now instead of

   @PreAuthorize("hasAuthority('FinanceHead') or hasAuthority('FinanceAdmin') or hasAuthority('Finance3') or hasAuthority('Finance2') or hasAuthority('Finance1')")
   @GetMapping("/test")
    public ResponseEntity<String> test1() {
        return new ResponseEntity<>("Test", HttpStatus.OK);
    }

I can simply go

@PreAuthorize("hasRole('ROLE_ADMIN_3')")
@GetMapping("/test")
public ResponseEntity<String> test1() {
    return new ResponseEntity<>("Test", HttpStatus.OK);
}

And if the request has any of the following roles:

ROLE_BOSS, ROLE_FINANCE_HEAD, ROLE_FINANCE_ADMIN, ROLE_FINANCE_3 

The request will be done, else a 403 is thrown.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文