当前位置: 首页 > 知识库问答 >
问题:

用于多种方法的MethodSecurityInterceptor

沃威
2023-03-14

要决定是否允许为给定用户调用服务方法,对被调用的方法影响所需的角色(使用MethodSecurityMetadataSource)对我来说是不够的,因为它还取决于传递给方法的参数。正如文档中所建议的,我可以编写一个自定义的AccessDecisionVoter并通过安全对象访问参数(在本例中是MethodInvocation)。

但是,我的授权逻辑在不同的方法中是不同的。例如,多个方法之间的参数可能不同,授权逻辑也会不同。

我看到两个选择:

  • 我可以在AccessDecisionVoter中使用条件逻辑来确定调用的方法和要使用的授权逻辑,但这似乎是一个丑陋的解决方案。
  • 我可以为每个方法定义一个MethodSecurityInterceptor来保护。根据Spring文档,MethodSecurityInterceptor用于保护许多方法,因此我想到还有另一种方法。

有哪些替代方案?

共有1个答案

虞正业
2023-03-14

我通过实现自己的AccessDecisionManager,将访问决策委托给我的特殊接口AccessDecisionStrategy,实现了这一点:

public interface AccessDecisionStrategy {

    void decide(Authentication authentication, MethodInvocation methodInvocation, ConfigAttribute configAttribute);

}

每种访问决策策略代表了不同的访问决策方式。

您可以轻松地实现自己的策略(即使是在其他语言中--例如Scala):

public class SomeStrategy implements AccessDecisionStrategy { ...
public class MethodSecurityAccessDecisionManager implements AccessDecisionManager {

    private Map<String, AccessDecisionStrategy> strategyMap;

    public MethodSecurityAccessDecisionManager(Map<String, AccessDecisionStrategy> strategyMap) {
        this.strategyMap = strategyMap;
    }

    @Override
    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
        ConfigAttribute configAttribute = getSingleConfigAttribute(configAttributes);
        AccessDecisionStrategy accessDecisionStrategy = strategyMap.get(configAttribute.getAttribute());
        if (accessDecisionStrategy == null) {
            throw new IllegalStateException("AccessDecisionStrategy with name "
                    + configAttribute.getAttribute() + " was not found!");
        }
        try {
            accessDecisionStrategy.decide(authentication, (MethodInvocation) object, configAttribute);
        } catch (ClassCastException e) {
            throw new IllegalStateException();
        }
    }

    private ConfigAttribute getSingleConfigAttribute(Collection<ConfigAttribute> configAttributes) {
        if (configAttributes == null || configAttributes.size() != 1) {
            throw new IllegalStateException("Invalid config attribute configuration");
        }
        return configAttributes.iterator().next();
    }

    @Override
    public boolean supports(ConfigAttribute attribute) {
        return true;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return clazz.equals(MethodInvocation.class);
    }
}
@Secured("GetByOwner")
FlightSpotting getFlightSpotting(Long id);
<bean id="methodSecurityAccessDecisionManager"
      class="some.package.MethodSecurityAccessDecisionManager">

    <constructor-arg>
        <map>
            <entry key="GetByOwner">
                <bean class="some.package.GetByOwnerStrategy"/>
            </entry>

            <entry key="SomeOther">
                <bean class="some.package.SomeOtherStrategy"/>
            </entry>
        </map>
    </constructor-arg>

</bean>

若要插入访问决策管理器,请键入:

<sec:global-method-security secured-annotations="enabled"
                            access-decision-manager-ref="methodSecurityAccessDecisionManager">
</sec:global-method-security>

我还实现了helper类来处理MethodInvocation参数:

import org.aopalliance.intercept.MethodInvocation;

public class MethodInvocationExtractor<ArgumentType> {

    private MethodInvocation methodInvocation;

    public MethodInvocationExtractor(MethodInvocation methodInvocation) {
        this.methodInvocation = methodInvocation;
    }

    public ArgumentType getArg(int num) {
        try {
            Object[] arguments = methodInvocation.getArguments();
            return (ArgumentType) arguments[num];
        } catch (ClassCastException | ArrayIndexOutOfBoundsException e) {
            throw new IllegalStateException();
        }
    }

}

现在,您可以轻松地在策略代码中提取有趣的参数来做出决策:

MethodInvocationExtractor<Long> extractor = new MethodInvocationExtractor<>(methodInvocation);
Long id = extractor.getArg(0);
 类似资料:
  • 问题内容: 我想使用Spring Security保护我的服务层。如文档中所述,我需要使用a 来检查是否允许方法调用。 要确定是否允许给定用户调用服务方法,对我来说影响对调用的方法的必需角色(使用)是不够的,因为这也取决于传递给方法的参数。如文档中所建议,我可以编写一个自定义并通过安全对象访问参数(在这种情况下)。 但是,我的授权逻辑在所有方法中都不同。例如,多个方法之间的参数可能不同,并且授权逻

  • 问题内容: 随处可见Java 8 lambda。当我向接口添加其他方法时,为什么这会给我一个错误: 在没有第二种方法的情况下可以正常工作:“ public int getID(String name) 问题答案: Java lambda和方法引用只能分配给 功能接口 。从Java SE 8 API中,软件包描述: 每个函数接口都有一个单一的抽象方法,称为该函数接口的函数方法,lambda表达式的参

  • 本文向大家介绍基于spring 方法级缓存的多种实现,包括了基于spring 方法级缓存的多种实现的使用技巧和注意事项,需要的朋友参考一下 方案实施 1、 spring和ehcache集成 主要获取ehcache作为操作ehcache的对象。 spring.xml中注入ehcacheManager和ehCache对象,ehcacheManager是需要加载ehcache.xml配置信息,创建ehc

  • 当我在一个方法中有多个操作时,saveUser方法不会保存用户对象名称更改。如果我在saveUser服务方法之上使用@Transactional(传播=传播。REQUIRED),它可以正常工作。当另一个类创建一个新的User对象并设置其所有值并调用createUser方法时,它可以正常工作。为什么我需要@Transactional用于saveUser方法?在什么情况下我需要包含@Transacti

  • 本文向大家介绍java命令执行jar包的多种方法(四种方法),包括了java命令执行jar包的多种方法(四种方法)的使用技巧和注意事项,需要的朋友参考一下 大家都知道一个java应用项目可以打包成一个jar,当然你必须指定一个拥有main函数的main class作为你这个jar包的程序入口。 具体的方法是修改jar包内目录META-INF下的MANIFEST.MF文件。 比如有个叫做test.j

  • 本文向大家介绍JavaScript数组去重的多种方法(四种),包括了JavaScript数组去重的多种方法(四种)的使用技巧和注意事项,需要的朋友参考一下 数组去重,一般需求是给你一个数组,调用去重方法,返回数值副本,副本中没有重复元素。一般来说,两个元素通过 === 比较返回 true 的视为相同元素,需要去重,所以,1 和 "1" 是不同的元素,1 和 new Number(1) 是不同的元素