Java 用于spring boot中多个方法的MethodSecurityInterceptor
这与Mickeel Marrache关于如何使用不同方法的授权逻辑保护服务的回答有关 我更喜欢Maciej Ziarko使用而不是接受的响应,因为它使用相同的注释Java 用于spring boot中多个方法的MethodSecurityInterceptor,java,spring,spring-security,spring-boot,Java,Spring,Spring Security,Spring Boot,这与Mickeel Marrache关于如何使用不同方法的授权逻辑保护服务的回答有关 我更喜欢Maciej Ziarko使用而不是接受的响应,因为它使用相同的注释@Secured和不同的自定义参数 因为我使用的是没有XML配置的SpringBoot,所以我花了一段时间才弄明白如何做 这是我的答案 它只是解释了如何用Java配置替换xml配置。(在我的更改之后,我将添加原始答案“以防万一”。) 要替换xml配置,请执行以下操作: <sec:global-method-security sec
@Secured
和不同的自定义参数
因为我使用的是没有XML配置的SpringBoot,所以我花了一段时间才弄明白如何做
这是我的答案
它只是解释了如何用Java配置替换xml配置。(在我的更改之后,我将添加原始答案“以防万一”。)
要替换xml配置,请执行以下操作:
<sec:global-method-security secured-annotations="enabled"
access-decision-manager-ref="methodSecurityAccessDecisionManager">
</sec:global-method-security>
这两项工作都可以使用Java配置完成,如下所示:
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);
}
}
仅为了完整性,当用户不应继续时,已实施的策略必须返回AccessDeniedException
或InsufficientAuthenticationException
。以下是访问参数和所有参数的示例:
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");
}
}
}
每个访问决策策略代表了不同的访问决策方式
您可以轻松地实施自己的策略(即使使用其他语言,例如Scala):
公共类SomeStrategy实现AccessDecisionStrategy{
如您所见,我的AccessDecisionManager有一个策略图。manager使用的策略基于注释参数
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);
}
}
您可以实施和配置任意数量的策略:
<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>
我还实现了帮助器类来处理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();
}
}
}
import org.aopalliance.intercept.MethodInvocation;
公共类方法调用提取器{
私有方法调用方法调用;
公共MethodInvocation提取器(MethodInvocation MethodInvocation){
this.methodInvocation=methodInvocation;
}
公共参数类型getArg(int num){
试一试{
Object[]arguments=methodInvocation.getArguments();
返回(ArgumentType)参数[num];
}catch(ClassCastException | ArrayIndexOutOfBoundsException e){
抛出新的非法状态异常();
}
}
}
现在,您可以轻松地在策略代码中提取有趣的参数来做出决策:
假设我想得到Long类型的参数0:
MethodInvocationExtractor<Long> extractor = new MethodInvocationExtractor<>(methodInvocation);
Long id = extractor.getArg(0);
MethodInvocationExtractor=newmethodinvocationextractor(methodInvocation);
Long id=extractor.getArg(0);
12年11月14日14:40回答
马切吉·齐亚科
<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>
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);