我有服务界面
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)实现的界面,所以exression this.compoundClass
实际上会正确评估吗?
最后但并非最不重要的是我怎样才能真正测试这个?*
* 我实际上并没有创建一个完成的应用程序,而是可配置的东西,比如用于特定类型的数据库搜索的框架。这意味着大多数授权和身份验证都必须来自实施者。
答案 0 :(得分:2)
请参阅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>
它没有它们(但是没有创建一个抽象的测试类)
这实际上是正确的方法
问题是你不能使用类参数的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);
}
}