Spring Security 组合角色的Keycloak Spring实现

gajydyqb  于 2023-01-20  发布在  Spring
关注(0)|答案(2)|浏览(185)

我有一个问题,我不能解决后,研究了很多。
我有一个客户端(应用程序)和角色,确保应用程序的密钥锁定。
在我的应用程序中,我用.hasRole()-方法检查用户或其他应用程序的角色是否与定义的角色匹配。
问题是我想合并角色并在应用程序中检查它们。
要访问我的应用程序,用户应具有“读”和“写”角色。
在Spring中,hasRole()方法一次只检查一个角色,hasAnyRole()方法检查是否有一个角色匹配。
有没有像hasAllRoles这样的方法?它检查所有的角色是否匹配?
一个请求是仅通过配置解决该问题,但应用程序中实现的方法是hasRole(),因此我认为仅通过应用程序内部Keycloak或www.example.com上的配置无法解决该问题Application.properties

pvcm50d1

pvcm50d11#

最简单的解决方案可能是找到一种方法,向决定“仅使用配置解决该问题”的人解释使用@PreAuthorize元数据是更好的解决方案:

  • 控制器代码未被访问控制“污染”:注解不在方法体中,并且只有在Spring Security中启用时才进行评估(这与conf中的访问控制没有区别)
  • 访问控制规则接近于访问点定义,这使其更具可读性(易于理解应用于特定路由和HTTP动词的内容)
  • SpEL比配置请求匹配器强大得多,你甚至可以定义自己的DSL来编写像@PreAuthorize("is(#username) or isNice() or onBehalfOf(#username).can('greet')")这样的表达式(这取自my tutorialsthe most advanced)。
  • 访问控制可以修饰任何@Component(包括@Service@Repository)的任何方法,而不仅仅是修饰了@RequestMapping或其偏差之一的@Controller的公共方法。

使用Spel,您可以做您需要做的事情(readwrite),还可以根据访问的资源本身(谁创建了它,它链接到什么,...)定义规则
试一试:

  • 添加@EnableMethodSecurity到你的安全配置类
  • 仅使用请求匹配器定义匿名访问的内容和需要身份验证的内容
  • 在控制器方法的正上方添加@PreAuthorize("hasRole('read') and hasRole('write')")
7hiiyaii

7hiiyaii2#

除了@ch4mp所解释的,我还想提供一些其他的原则。
首先是你的问题。你可以用两种方法来处理hasAllRoles。第一种是用AuthorizationManagers.allOf,第二种是用Spel:

http.authorizeHttpRequests((authorize) -> authorize
    .requestMatchers("/endpoint").access(
        allOf(hasAuthority("read"), hasAuthority("write"))
    )
)

以及

@PreAuthorize("hasAuthority('read') and hasAuthority('write')")

请继续阅读与您的评论相关的其他建议:
问题是我想合并角色并在应用程序中检查它们。

一颗豆子

将授权逻辑提取到组件中的一种好方法是在表达式中引用授权bean。
例如,您可以执行以下操作:

@Component("authz")
public final class MyAuthorizationDecider {
    public boolean check(MethodSecurityExpressionOperations operations) {
        // ... place authorization logic here
    }
}

然后你就可以:

@PreAuthorize("@authz.check(#root)")

(If我没有弄错,您仍然可以通过这种方法使用@ch4mp的库,只需从Java方法调用库的DSL,而不是在SpEL表达式中调用。)

层次结构

还有一种情况是一些权限隐含其他权限。对于您来说,message:write隐含message:read可能就是这种情况。在这种情况下,您的表达式可以通过在RoleHierarchy示例中编码这种关系来简化。

登录时

有时,在登录时Map权限可能会很有帮助。例如,USER的角色可能会转换为message:readADMIN的角色可能会转换为message:readmessage:write。也可能会转换为另一种方式。如果客户机授予了message:readmessage:write,则可能会转换为message:redact的单个权限。
如果在登录时执行此转换,则可以减少请求时的计算量,并且可以在单个位置推断授予的权限。
比如说,我们不去做

@PreAuthorize("hasAuthority('message:read') and hasAuthority('message:write')")

.authorizeHttpRequests((authorize) -> authorize
    .requestMatchers("/message/redact").access(
        allOf(hasAuthority("message:read"), hasAuthority("message:write"))
    )
)

你会这么做

@PreAuthorize("hasAuthority('message:redact')")

.authorizeHttpRequests((authorize) -> authorize
    .requestMatchers("/message/redact").hasAuthority("message:redact")
)

由于您使用的是Keycloak,因此在这种情况下,如果您是资源服务器,则可以考虑使用自定义JwtGrantedAuthoritiesConverter;如果您是客户端,则可以考虑使用GrantedAuthoritiesMapper,将Jwt授予的权限Map到与您在应用中执行的操作对应的权限。

相关问题