Java 如何从使用投票者的AccessDecisionManager引发信息异常

Java 如何从使用投票者的AccessDecisionManager引发信息异常,java,authorization,spring-security,Java,Authorization,Spring Security,我有以下情况:我的应用程序的授权机制是使用SpringSecurity实现的。中心类实现了AccessDecisionManager,并使用投票者(每个投票者都实现了AccessDecisionVoter)来决定是否授予对某些方法的访问权。统计投票的算法是自定义的: public class PermissionManagerImpl extends AbstractAccessDecisionManager { public void decide( Auth

我有以下情况:我的应用程序的授权机制是使用SpringSecurity实现的。中心类实现了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");
        }               
    }

}
公共类PermissionManagerImpl扩展了AbstractAccessDecisionManager{
公共无效裁决(
身份验证,
对象对象对象,
ConfigAttributeDefinition配置)抛出AccessDeniedException{
迭代器iter=getDecisionVoctors().Iterator();
布尔wasneed=false;
while(iter.hasNext()){
AccessDecisionVoter=(AccessDecisionVoter)iter.next();
int result=voter.vote(身份验证、对象、配置);
开关(结果){
//一些理货计算
}
}
如果(被拒绝){
抛出新的AccessDeniedException(“访问被拒绝”);
}               
}
}
在拒绝访问某个方法时,应用程序的客户端希望获得一个信息异常,该异常准确地指定拒绝访问的原因。这意味着将投票者的一些信息传递给决策经理。不幸的是,标准访问决策投票者传递回决策管理器的唯一信息是一个可能的返回值(访问被授予访问被放弃访问被拒绝

最好的方法是什么


谢谢。

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

由于您同时使用投票者和access决策管理器,因此在我看来,您有几个可用的选项:

  • 以某种形式的错误代码返回其他整数值;将授予的
    访问权
    访问权弃权
    和拒绝的
    访问权
    视为其典型值,但将任何其他整数视为带有错误代码的“拒绝访问权”。理想情况下,有一个可用的错误代码查找表-基本上是穷人的枚举
  • 在投票者中,像往常一样返回
    ACCESS\u DENIED
    ,并设置一些公共可访问的属性(在投票者对象本身上,或者在一些静态可访问的字段上),并说明错误原因。在manager中,如果自定义投票者拒绝访问,请检查属性以获取详细信息
  • 如上所述,在表决器内设置错误属性;但是要确保传入的
    身份验证
    实例是您自己的自定义子类之一,它提供了良好的 设置/检索此信息的位置
  • 从投票者本身中抛出一个
    AccessDeniedException
    (或合适的子类)。这并不理想,因为它以访问决策管理器中的逻辑为前提;但是您可以直接让这个冒泡出现,或者如果需要,可以在管理器中捕获它(自定义子类肯定会有好处),并在访问被拒绝时重新冒泡(类似于
    ProviderManager
    类使用其
    lastException
    变量所做的操作)

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

    您不能直接实现
    AccessDecisionManager
    ,而不使用投票者吗?然后,您可以抛出一个带有正确信息的
    AccessDeniedException
    。也许
    RoleVoter
    s不是您案例中使用的正确抽象。

    感谢您的回答

    我想我已经找到了一种非常优雅的方式来做我想做的事情,并且仍然使用标准的API。AccessDecisionVoter投票方法的第二个参数是安全对象。我可以在决策管理器和投票者之间创建一个契约,该对象属于一个特定的类/接口,它是一个包装器,通过它可以获取原始的安全对象,也可以由拒绝访问的投票者添加附加信息

    我在其他框架中也看到了类似的模式。与其他可能的解决方案相比,此解决方案具有以下优势:

    • 选民可以保持无国籍,因此他们可以是单身
    • 使用AccessDecisionVoter的标准接口,不添加新的返回值
    • 附加信息保存在一个对象中,该对象被自动丢弃,因为在AbstractDecisionManager的decision方法之后没有人使用它,因此不需要清除代码
    干杯