将 RoleHierarchy 应用于客户端角色

Apply RoleHierarchy to Client Roles

对于我的应用程序中的安全角色,我们定义了 RoleHierarchy,但是当我们尝试使用 @PreAuthorize("#oauth2.clientHasRole('somerole')") 检查客户端角色时,我们注意到默认情况下我们的 Hirarchy 不适用于客户端角色。

除了在 OAuth2MethodSecurityExpressionHandler 上设置 roleHierarchy 之外,是否还需要一些额外的配置?

正常的 OAuth2MethodSecurityExpressionHandler 不会将 RoleHierarchy 应用于 Client-Authorities。为了解决这个问题,我添加了我自己的 ExpressionHandler,它通过扩展它来实现。

public class HierarchicalOAuth2MethodSecurityExpressionHandler extends OAuth2MethodSecurityExpressionHandler {
    public HierarchicalOAuth2MethodSecurityExpressionHandler() {
        super();
    }

    @Override
    public StandardEvaluationContext createEvaluationContextInternal(Authentication authentication, MethodInvocation mi) {
        StandardEvaluationContext ec = super.createEvaluationContextInternal(authentication, mi);
        ec.setVariable("oauth2roles", new HierarchicalOAuth2SecurityExpressionMethods(authentication, getRoleHierarchy()));
        return ec;
    }
}

public class HierarchicalOAuth2SecurityExpressionMethods extends OAuth2SecurityExpressionMethods {

    private RoleHierarchy roleHierarchy;
    private Authentication authentication;

    public HierarchicalOAuth2SecurityExpressionMethods(Authentication authentication, RoleHierarchy roleHierarchy) {
        super(authentication);
        this.authentication = authentication;
        this.roleHierarchy = roleHierarchy;
    }

    @Override
    public boolean clientHasAnyRole(String... roles) {
        if (authentication instanceof OAuth2Authentication) {
            OAuth2Request clientAuthentication = ((OAuth2Authentication) authentication).getOAuth2Request();
            Collection<? extends GrantedAuthority> clientAuthorities = roleHierarchy.getReachableGrantedAuthorities(clientAuthentication.getAuthorities());
            if (clientAuthorities != null) {
                Set<String> roleSet = AuthorityUtils.authorityListToSet(clientAuthorities);
                for (String role : roles) {
                    if (roleSet.contains(role)) {
                        return true;
                    }
                }
            }
        }

        return false;
    }
}

现在我可以根据需要选择使用#oauth2roles.clientHasAnyRole(...)。