2013-02-21 48 views
2

参考属性我有服务接口@PreAuthorize:在实施

public interface CompoundService<T extends Compound> { 

    T getById(final Long id); 

    //... 
} 

和抽象实现

public abstract class CompoundServiceImpl<T extends Compound> 
     implements CompoundService<T> { 

    //... 

    private Class<T> compoundClass; 

    //... 
} 

Compound每个实现需要它的延伸CompoundService和它自己的服务类自己的服务接口,延伸CompoundServiceImpl

我现在想在CompoundService的我的方法中添加基本安全uisng注释。据我了解,我必须将它们添加到接口中而不是实际的实现中。由于用户可以针对Compound的不同实现具有不同的角色,因此我必须考虑到这一点。在@PreAuthorize的含义我想获得Compound实现的名称,例如。 compoundClass.getSimpleName()。所以,我得到这样的:

public interface CompoundService<T extends Compound> { 

    @PreAuthorize("hasRole('read_' + #root.this.compoundClass.getSimpleName())") 
    T getById(final Long id); 

    //... 
} 

这基本上就是在这里提到:

https://jira.springsource.org/browse/SEC-1640

但没有例子,我并没有真正得到解决。那么我应该使用this?或如上#root.this

我的第二个问题是,因为这是一个将由代理实现的接口(从spring开始),预期this.compoundClass实际上是否正确评估?

最后但并非最不重要的我怎么能实际测试呢?*

* 我不是真正创建一个完成的应用程序,但一些配置,像的具体类型的数据库搜索的框架。这意味着大多数授权和认证都必须来自实施者。

回答

2
  1. 单元测试

看到http://www.lancegleason.com/blog/2009/12/07/unit-testing-spring-security-with-annotations

自认为是一个古老的教程,您可能需要更改被引用的模式版本。但更重要的是,那里显示的SecurityContext.xml配置不适用于Spring Security 3.有关正确的配置,请参阅Spring Security - multiple authentication-providers

我并不需要提到的依赖关系:

<dependency> 
    <groupId>org.aspectj</groupId> 
    <artifactId>aspectjweaver</artifactId> 
</dependency> 
<dependency> 
    <groupId>org.springframework.security</groupId> 
    <artifactId>spring-security-core-tiger</artifactId> 
</dependency> 

它的工作没有它们(但没有创建抽象测试类)

  • root.this

  • 这其实是正确的做法

    问题是您无法使用类参数的getSimpleName()。有关深入讨论,请参阅http://forum.springsource.org/showthread.php?98570-Getting-Payload-Classname-in-Header-Enricher-via-SpEL

    此处显示的解决方法对我没有多大帮助。所以,我想出了这个非常简单的解决方案:

    只是字符串属性String compoundClassSimpleName添加到CompoundServiceImpl,并在构造函数中设置它(这是由子类调用):

    Public abstract class CompoundServiceImpl<T extends Compound> 
        implements CompoundService<T> { 
    
        private String compoundClassSimpleName; 
    
        //... 
    
        public ChemicalCompoundServiceImpl(Class<T> compoundClass) { 
         this.compoundClass = compoundClass; 
         this.compoundClassSimpleName = compoundClass.getSimpleName(); 
        } 
    
        //... 
    
        public String getCompoundClassSimpleName(){ 
         return compoundClassSimpleName; 
        } 
    } 
    

    和她的服务实现上述抽象服务:

    public class TestCompoundServiceImpl extends CompoundServiceImpl<TestCompound> 
         implements TestCompoundService { 
    
        //... 
    
        public TestCompoundServiceImpl() { 
         super(TestCompound.class); 
        } 
    
        //... 
    
    } 
    

    和最终的@PreAuthorize注释的用法:

    public interface CompoundService<T extends Compound> { 
    
        @PreAuthorize("hasRole('read_' + #root.this.getCompoundClassSimpleName())") 
        public T getById(final Long id); 
    } 
    

    对于上述示例,表达式将评估为名为“read_TestCompound”的角色。

    完成!

    由于经常的解决方案很简单,但越来越有皮塔...

    编辑:

    的完整性测试类:

    @RunWith(SpringJUnit4ClassRunner.class) 
    @ContextConfiguration(locations = { 
         "classpath:ApplicationContext.xml", 
         "classpath:SecurityContext.xml" 
         }) 
    public class CompoundServiceSecurityTest { 
    
        @Autowired 
        @Qualifier("testCompoundService") 
        private TestCompoundService testCompoundService; 
    
        public CompoundServiceSecurityTest() { 
        } 
    
    
        @Before 
        public void setUp() { 
         SecurityContextHolder.getContext().setAuthentication(
          new UsernamePasswordAuthenticationToken("user_test", "pass1")); 
        } 
    
        @Test 
        public void testGetById() { 
         System.out.println("getById"); 
         Long id = 1000L; 
         TestCompound expResult = new TestCompound(id, "Test Compound"); 
         TestCompound result = testCompoundService.getById(id); 
         assertEquals(expResult, result); 
        } 
    }