gpt4 book ai didi

java - Spring Boot中多种方法的MethodSecurityInterceptor

转载 作者:行者123 更新时间:2023-11-30 03:48:31 25 4
gpt4 key购买 nike

这与this question的答案有关作者:Mickael Marrache,介绍如何使用不同方法中不同的授权逻辑来保护服务。

我更喜欢 Maciej Ziarko 使用 Method Security AccessDecisionManager 提供的响应而不是接受的那个,因为它使用相同的注释 @Secured 和不同的自定义参数。

由于我使用的是没有 XML 配置的 Spring-Boot,所以我花了一些时间才弄清楚如何做到这一点。

所以,这是我的答案。

它只是解释了如何用 Java Config 配置替换 xml 配置。

最佳答案

(更改后,我将添加原始答案“以防万一”。)

为了替换xml配置:

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

碰巧注释@EnableGlobalMethodSecurity没有办法在那里指定accessDecisionManager。您必须扩展 GlobalMethodSecurityConfiguration 并重写 AccessDecisionManager 方法。

并根据原始帖子的需要实现和配置尽可能多的策略

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

这两个问题都可以使用 Java Config 来完成,如下所示:

import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;


@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {

private final Logger logger = LoggerFactory.getLogger(getClass());

public AccessDecisionManager accessDecisionManager() {

logger.debug("accessDecisionManager config...");

Map<String, AccessDecisionStrategy> strategyMap = new HashMap<String, AccessDecisionStrategy>();

strategyMap.put("GetByOwner", new GetByOwnerStrategy());

return new MethodSecurityAccessDecisionManager(strategyMap);
}

}

最后,简单明了的网络安全配置。请注意,我使用的是“RestWebSecurity...”,您可以随意命名它。

@Configuration
public class WebSecurityConfig {

@Configuration
@Order(1)
public static class RestWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/**").authenticated()
.and()
.httpBasic()
.and()
.csrf().disable();
}
}
}

为了完整起见,当用户不应继续操作时,已实现的策略必须返回 AccessDeniedExceptionInsufficientAuthenticationException。这是访问参数和所有内容的示例:

public class GetByOwnerStrategy implements AccessDecisionStrategy {
@Override
public void decide(Authentication authentication,
MethodInvocation methodInvocation, ConfigAttribute configAttribute) {

MethodInvocationExtractor<Object> extractor = new MethodInvocationExtractor<>(methodInvocation);
Person person = (Person) extractor.getArg(0);
String userId = (String) extractor.getArg(1);

String username = authentication.getName();

if (! ((userId.equals(username)) && (person.getSomeData().equals("SOMETHING") ) && ....) {
throw new AccessDeniedException("Not enough privileges");
}
}
}

================= 原答案=======================

我通过实现自己的 AccessDecisionManager 来实现这一目标,该管理器将访问决策委托(delegate)给我的特殊接口(interface) AccessDecisionStrategy:

public interface AccessDecisionStrategy {

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

}

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

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

公共(public)类 SomeStrategy 实现 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>

我还实现了帮助程序类来处理 MethodInitation 参数:

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);

于 2012 年 11 月 14 日 14:40 回答
马切伊·齐亚科

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

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