gpt4 book ai didi

java - 多个方法的 MethodSecurityInterceptor

转载 作者:塔克拉玛干 更新时间:2023-11-03 05:10:21 31 4
gpt4 key购买 nike

我想使用 Spring Security 保护我的服务层。如文档中所述,我需要使用 MethodSecurityInterceptor 来检查是否允许调用方法。

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

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

我看到两个选项:

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

方法调用后的访问决策存在相同的问题(使用 AfterInvocationProvider)。

有哪些替代方案?

最佳答案

我通过实现自己的 AccessDecisionManager 将访问决策委托(delegate)给我的特殊接口(interface) AccessDecisionStrategy 来实现这一点:

public interface AccessDecisionStrategy {

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

}

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

您可以轻松实现自己的策略(甚至使用其他语言 - 例如 Scala):

public class SomeStrategy implements AccessDecisionStrategy { ...

如您所见,我的 AccessDecisionManager 有一个策略图。经理使用的策略基于注释参数。

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 注释和作为策略名称的参数放在一起:

@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>

要注入(inject)您输入的访问决策管理器:

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

我还实现了帮助程序类来处理 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();
}
}

}

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

假设我想获取 Long 类型的参数编号 0:

MethodInvocationExtractor<Long> extractor = new MethodInvocationExtractor<>(methodInvocation);
Long id = extractor.getArg(0);

关于java - 多个方法的 MethodSecurityInterceptor,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13376202/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com