2014-09-04 63 views
1

如何從彈簧安全等全球性法的安全保護,切入點與@EnableGlobalMethodSecurity

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

一個端口的Spring Java-配置

@EnableGlobalMethodSecurity 
@Configuration 
public class MyConfiguration extends WebSecurityConfigurerAdapter { 

這裏有http://forum.spring.io/forum/spring-projects/security/726615-protect-pointcut-in-java-configuration

回答

2

一個simmilar問題有它一個解決方法。安全點信息保存在MethodSecurityMetadataSource實現中(然後由MethodInterceptor使用),因此我們必須創建額外的MethodSecurityMetadataSource。正如春季論壇帖子中所提到的,xml切入點配置保存在MapBasedMethodSecurityMetadataSource中,並由ProtectPointcutPostProcessor進行處理。我們還需要一個ProtectPointcutPostProcessor的實例。不幸的是這個類是最終的,包私人所以有2種選擇:

  1. 創建自己的類和複製/粘貼原來的全部內容(這是我做的)
  2. 更改類改性劑與反射和創建原始一個實例(沒有這樣做,所以不知道是否會工作的優良)

然後在您的環境中創建以下豆:

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

我們已經創建了必要的豆類,現在我們必須告訴spring使用它們。我假設你正在擴展GlobalMethodSecurityConfiguration。默認情況下它會創建DelegatingMethodSecurityMetadataSource,其中包含其他MethodSecurityMetadataSource的列表。根據你想要什麼來實現,可以有以下選擇:

  1. 如果你想保留所有其他MethodSecurityMetadataSource S(如藥粥解析@Secured註釋),你可以在委託元數據源的擴展列表覆蓋下面的方法:

    @Override 
    protected MethodSecurityMetadataSource customMethodSecurityMetadataSource() { 
        return mappedMethodSecurityMetadataSource(); 
    } 
    

它會在列表中注入它的第一個地方,雖然這可能會導致一些問題。

如果你想保持其他來源,但希望你是最後一個在列表中,然後覆蓋下面的方法
  • :如果你想

    @Override 
    public MethodSecurityMetadataSource methodSecurityMetadataSource() { 
        DelegatingMethodSecurityMetadataSource metadataSource = (DelegatingMethodSecurityMetadataSource) super.methodSecurityMetadataSource(); 
        metadataSource.getMethodSecurityMetadataSources().add(mappedMethodSecurityMetadataSource()); 
        return metadataSource; 
    } 
    
  • 您源是唯一一個(你不想使用@Secured或任何其他註釋),那麼你可以重寫同樣的方法,只是用不同的內容

    @Override 
    public MethodSecurityMetadataSource methodSecurityMetadataSource() { 
        return mappedMethodSecurityMetadataSource(); 
    } 
    
  • 就是這樣!我希望這將有助於

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

    這樣我就不需要重複的代碼這個春季班。

    乾杯