2

我有以下情况:我的应用程序的授权机制是使用Spring security实现的。中心类实现AccessDecisionManager并使用投票者(每个投票者都实现AccessDecisionVoter)来决定是否授予对某些方法的访问权限。计算选票的算法是自定义的:

public class PermissionManagerImpl extends AbstractAccessDecisionManager {

    public void decide(
            Authentication authentication,
            Object object,
            ConfigAttributeDefinition config) throws AccessDeniedException {
        Iterator<?> iter = getDecisionVoters().iterator();
        boolean wasDenied = false;

        while (iter.hasNext()) {
            AccessDecisionVoter voter = (AccessDecisionVoter) iter.next();
            int result = voter.vote(authentication, object, config);

            switch (result) {
                // Some tallying calculations
            }
        }

        if (wasDenied) {
            throw new AccessDeniedException("Access is denied");
        }               
    }

}

在拒绝对某个方法的访问后,应用程序的客户端有兴趣获得一个信息异常,该异常指定了拒绝访问的确切原因。这意味着将一些信息从选民传递给决策经理。不幸的是,标准AccessDecisionVoter传递回决策管理器的唯一信息是可能的返回值之一(ACCESS_GRANTEDACCESS_ABSTAINACCESS_DENIED)。

最好的方法是什么?

谢谢。

4

3 回答 3

3

好吧,在这种情况下,AccesssDecisionVoter接口实际上返回了一个。int当然,内置的投票者实现总是只返回您提到的三个常量之一(这些是标准访问决策管理器检查的内容),但是它们实际上并没有任何额外的返回 -RoleVoter例如将拒绝当且仅当主体没有所需的角色时才访问。

由于您使用自己的选民和访问决策管理器实现,因此我认为您有几个可用的选项:

  1. 以某种形式的错误代码返回其他整数值;将ACCESS_GRANTED,ACCESS_ABSTAINACCESS_DENIED视为它们的典型值,但将任何其他整数视为带有错误代码的“拒绝访问”。理想情况下,有一个可用的错误代码查找表——本质上是一个穷人的枚举。
  2. 在你的投票者中,ACCESS_DENIED像往常一样返回,并设置一些可公开访问的属性(在投票者对象本身或一些静态可访问的字段上)以及错误原因。在您的经理中,如果您的自定义选民拒绝访问,请检查属性以获取详细信息。
  3. 如上,在voter中设置一个error属性;但要确保Authentication传入的实例是您自己的自定义子类之一,它提供了设置/检索此信息的良好位置。
  4. AccessDeniedException从您的选民本身中抛出一个(或合适的子类)。这并不理想,因为它预设了访问决策管理器中的逻辑;但是您可以直接让这个冒泡,或者如果需要在管理器中捕获它(自定义子类肯定会对此有好处)并在访问确实被拒绝时重新抛出(类似于ProviderManager该类对其lastException变量所做的事情)。

这些都不是明显正确和优雅的答案,但是您应该能够从最合适的答案中获得可行的答案。由于选民框架内没有明确支持沟通原因(从根本上说,这是一个直接的布尔响应),我认为你不能做得更好。

于 2009-02-04T12:18:08.310 回答
2

感谢回答的人。

我想我找到了一种非常优雅的方式来做我想做的事情,并且仍然使用标准的 voters API。AccessDecisionVoter的投票方法的第二个参数是安全对象。我可以在决策经理和选民之间创建一个合同,这个对象是一个特定的类/接口,它是一个包装器,通过它可以获取原始的安全对象,并且拒绝的选民也可以添加其他信息使用权。

我在其他框架中也看到了这样的模式。与其他可能的解决方案相比,该解决方案具有以下优点:

  • 选民可以保持无国籍状态,因此他们可以是单身人士
  • 使用 AccessDecisionVoter 的标准接口,没有添加新的返回值
  • 附加信息保存在自动丢弃的对象中,因为在AbstactDecisionManager决定方法之后没有人使用它,因此不需要清理代码

干杯。

于 2009-02-05T11:48:32.003 回答
1

AccessDecisionManager不能不使用选民直接实施吗?然后,您可以AccessDeniedException使用正确的信息抛出一个。也许RoleVoters 不是在您的情况下使用的正确抽象。

于 2009-02-04T12:28:43.687 回答