使用@EnableGlobalMethodSecurity的spring-security global-method-security保护切入点

时间:2014-09-04 14:10:49

标签: spring spring-security

如何从一个端口

<sec:global-method-security secured-annotations="disabled">
    <sec:protect-pointcut expression='execution(* x.y.z.end*(..))' access='...' />

弹簧java-config

@EnableGlobalMethodSecurity
@Configuration
public class MyConfiguration extends WebSecurityConfigurerAdapter {

这里有一个类似的问题http://forum.spring.io/forum/spring-projects/security/726615-protect-pointcut-in-java-configuration

2 个答案:

答案 0 :(得分:2)

有一个解决方法。安全点信息保存在MethodSecurityMetadataSource实现中(然后由MethodInterceptor使用),因此我们必须创建一个额外的MethodSecurityMetadataSource。正如Spring论坛帖子中所提到的,xml切入点配置保存在MapBasedMethodSecurityMetadataSource中并由ProtectPointcutPostProcessor处理。我们还需要一个ProtectPointcutPostProcessor的实例。不幸的是,这个类是final和package-private,所以有两个选项:

  1. 创建自己的课程并复制/粘贴原始课程的全部内容(这就是我的所作所为)
  2. 使用反射更改类修饰符并创建原始修饰符的实例(没有做过,所以不知道它是否能正常工作)
  3. 然后在您的上下文中创建以下bean:

    @Bean
    public Map<String, List<ConfigAttribute>> protectPointcutMap() {
        Map<String, List<ConfigAttribute>> map = new HashMap<>();
    
        // all the necessary rules go here
        map.put("execution(* your.package.service.*Service.*(..))", SecurityConfig.createList("ROLE_A", "ROLE_B"));
    
        return map;
    }
    
    @Bean
    public MethodSecurityMetadataSource mappedMethodSecurityMetadataSource() {
    
        // the key is not to provide the above map here. this class will be populated later by ProtectPointcutPostProcessor
        return new MapBasedMethodSecurityMetadataSource();
    }
    
    // it's either the original spring bean created with reflection or your own copy of it
    @Bean
    public ProtectPointcutPostProcessor pointcutProcessor() {
        ProtectPointcutPostProcessor pointcutProcessor = new ProtectPointcutPostProcessor((MapBasedMethodSecurityMetadataSource) mappedMethodSecurityMetadataSource());
        pointcutProcessor.setPointcutMap(protectPointcutMap());
        return pointcutProcessor;
    }
    

    我们已经创建了必要的bean,现在我们必须告诉spring使用它们。我假设您正在延长GlobalMethodSecurityConfiguration。默认情况下,它会创建DelegatingMethodSecurityMetadataSource,其中包含其他MethodSecurityMetadataSource的列表。根据您想要实现的目标,您有以下选择:

    1. 如果要保留所有其他MethodSecurityMetadataSource(如用于解析@Secured注释的那些),可以通过覆盖以下方法来扩展委派元数据源中的列表:

      @Override
      protected MethodSecurityMetadataSource customMethodSecurityMetadataSource() {
          return mappedMethodSecurityMetadataSource();
      }
      
    2. 它会将它注入列表中的第一位,但这可能会导致一些问题。

      1. 如果您想保留其他来源,但希望您的列表中的最后一个,则覆盖以下方法:

        @Override
        public MethodSecurityMetadataSource methodSecurityMetadataSource() {
            DelegatingMethodSecurityMetadataSource metadataSource = (DelegatingMethodSecurityMetadataSource) super.methodSecurityMetadataSource();
            metadataSource.getMethodSecurityMetadataSources().add(mappedMethodSecurityMetadataSource());
            return metadataSource;
        }
        
      2. 如果您希望您的来源是唯一的(您不想使用@Secured或任何其他注释),那么您可以覆盖相同的方法,只是使用不同的内容

        @Override
        public MethodSecurityMetadataSource methodSecurityMetadataSource() {
            return mappedMethodSecurityMetadataSource();
        }
        
      3. 是的,那就是它!我希望它会有所帮助

答案 1 :(得分:1)

我关注了@marhewa的评论,并且能够通过定义以下bean来使用类ProtectPointcutPostProcessor的Spring版本

  /**
   * Needed to use reflection because I couldn't find a way to instantiate a
   * ProtectPointcutPostProcessor via a BeanFactory or ApplicationContext. This bean will process
   * the AspectJ pointcut defined in the map; check all beans created by Spring; store the matches
   * in the MapBasedMethodSecurityMetadataSource bean so Spring can use it during its checks
   * 
   * @return
   * @throws Exception
   */
  @Bean(name = "protectPointcutPostProcessor")
  Object protectPointcutPostProcessor() throws Exception {
    Class<?> clazz =
        Class.forName("org.springframework.security.config.method.ProtectPointcutPostProcessor");

    Constructor<?> declaredConstructor =
        clazz.getDeclaredConstructor(MapBasedMethodSecurityMetadataSource.class);
    declaredConstructor.setAccessible(true);
    Object instance = declaredConstructor.newInstance(pointcutMethodMetadataSource());
    Method setPointcutMap = instance.getClass().getMethod("setPointcutMap", Map.class);
    setPointcutMap.setAccessible(true);
    setPointcutMap.invoke(instance, pointcuts());

    return instance;
  }

这样我就不需要复制这个Spring类的代码了。

干杯