spring-security - @预授权: reference property in implementing class

标签 spring-security spring-el

我有服务接口(interface)

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 的服务接口(interface)和扩展 CompoundServiceImpl 的自己的服务类。

我现在想向 CompoundService 中的方法添加基本的安全性 UISNG 注释。据我了解,我必须将它们添加到接口(interface)中,而不是实际的实现中。由于用户可以针对 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)实现的接口(interface),表达式 this.compoundClass 实际上会正确评估吗?

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

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

最佳答案

  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

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

    只需将字符串属性StringcompoundClassSimpleName添加到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);
         }
    }
    

    关于spring-security - @预授权: reference property in implementing class,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15001653/

    相关文章:

    spring - 将自定义 SecurityExpressionOperations 中的方法注册为 Spring SpEL 函数

    java - Spring Security 5 - 我的自定义 UserDetailsS​​ervice 未被调用

    java - HttpSecurity、WebSecurity 和 AuthenticationManagerBuilder

    java - 使用不同用户名登录时获取 "Maximum sessions of 1 for this principal exceeded"

    grails - 将用户保留在Grails的Config.groovy列表中

    java - Spring Integration DSL - 可访问 header 的出站网关

    java - 使用 Spring 表达式语言从两个列表中进行选择

    templates - 根据 thymeleaf 中的其他变量选择上下文变量属性(动态)

    java - 如何仅在特定 Controller 中定义的路径上启用 Java Spring 安全性?

    java - Spring Security 中的 Spring Expression Language (SpEL) 比较对象使用 equals() 或 ==?