【问题标题】:@PreAuthorize: reference property in implementing class@PreAuthorize:实现类中的引用属性
【发布时间】:2013-02-06 17:47:18
【问题描述】:

我有服务接口

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)实现的接口中,所以 experession this.compoundClass 实际上会正确评估吗?

最后但并非最不重要的一点是,我该如何实际测试呢?*

* 我实际上并没有创建一个完成的应用程序,而是一些可配置的东西,比如用于特定类型数据库搜索的框架。这意味着大多数授权和身份验证内容必须来自实施者。

【问题讨论】:

    标签: spring-security spring-el


    【解决方案1】:
    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>
    

    没有它们也可以工作(但是没有创建抽象测试类)

    1. 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”的角色。

    完成!

    解决方案通常非常简单,但要达到目的需要 PITA...

    编辑:

    为了完整性测试类:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-05-04
      • 2016-04-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-11
      相关资源
      最近更新 更多