英文:
Spring Boot Test @PreAuthorize in a Library Module
问题
我有一个使用Spring Boot 1.5.21编写的库模块。
该库有一个带有@Service
注解的类,其中一些方法带有@PreAuthorize
注解,只允许具有ADMIN权限的用户执行某些操作,例如删除操作。
然后我有一个使用该库的Spring Boot应用程序。如果我运行该应用程序并进行手动测试,它可以正常工作。只有管理员可以进行删除操作。我想为此编写测试。
我考虑为模块和主应用程序分别编写测试。在模块中,我可以成功地对操作进行单元测试。但是我在测试@PreAuthorize
时遇到了问题,因为安全上下文不存在于模块中,而是存在于主应用程序中。有没有办法在模块中测试该注解,而不是在主应用程序中呢?
我库中相关的代码如下:
@Service
public class MyService {
@PreAuthorize("hasAuthority('ADMIN')")
public void delete (long id){
.....
}
}
@RunWith(SpringRunner.class)
public class MyServiceTest {
private MyService service;
@Test
@WithAnonymousUser
public void deleteShouldFailIfAnonymous() {
... 验证抛出异常
}
@Test
@WithMockUser(authorities = 'USER')
public void deleteShouldFailIfNotAdmin() {
... 验证抛出异常
}
@Test
@WithMockUser(authorities = 'ADMIN')
public void deleteShouldPass() {
... 应该通过
}
}
我尝试添加@EnableGlobalMethodSecurity(prePostEnabled = true)
,但没有成功。正如前面所说,SecurityConfiguration会在主应用程序中加载,而在库模块中不存在。
我是否可以在模块中测试@PreAuthorize
,还是应该将其移到主应用程序中?我希望尽可能将其保留在模块中。或者也许我可以为测试创建一个上下文,但不知道如何做到这一点。
英文:
I have a library-module written using Spring Boot 1.5.21.
The library has a @Service
with some methods annotated with @PreAutorize
allowing only users with ADMIN authority to perform some actions, for example a delete.
Then I have a Spring Boot Application that uses that library. If I run the app and manually test it, it works. Only ADMINs can delete. I'd like to write test for it.
I was thinking in writing separate test for module and for the main app. In my module I can successfully unit test the operations. But I'm having troubles testing the @PreAuthotize
, because the security context does not exist in the module, but in the main app. Is there a way to test that annotation in the module, and not in the main app?
The relevant code of my library:
@Service
public class MyService {
@PreAuthorize("hasAuthority('ADMIN')")
public void delete (long id){
.....
}
}
@RunWith(SpringRunner.class)
public class MyServiceTest {
private MyService service;
@Test
@WithAnonymousUser
public void deleteShouldFailIfAnonymous() {
... Verify exception thrown
}
@Test
@WithMockUser(authorities = 'USER')
public void deleteShouldFailIfNotAdmin() {
... Verify exception thrown
}
@Test
@WithMockUser(authorities = 'ADMIN')
public void deleteShouldPass() {
... Should pass
}
}
I've trying adding @EnableGlobalMethodSecurity(prePostEnabled = true)
but with no luck. And as said, the SecurityConfiguration is loaded in the main app, it does not exist in the library-module.
Can I test the @PreAuthorize
in the module or should I move it to the main app? I'd like to have it i the module if possible. Or maybe I can create a Context only for testing, but don't know how to do it.
答案1
得分: 0
你可以使用MockMvc进行测试。这将有助于模块测试,尤其是在集成测试的情况下。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@WebAppConfiguration
public class SecurityTests {
@Autowired
private WebApplicationContext context;
private MockMvc mvc;
@Before
public void setup() {
mvc = MockMvcBuilders.webAppContextSetup(context).apply(springSecurity()).build();
}
@WithMockUser(roles="ADMIN")
@Test
public void withMockUser() {
mvc.perform(get("......"))
}
}
英文:
You can use the MockMvc to test. This will help with module testing incase of integration testing.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@WebAppConfiguration
public class SecurityTests {
@Autowired
private WebApplicationContext context;
private MockMvc mvc;
@Before
public void setup() {
mvc = MockMvcBuilders.webAppContextSetup(context).apply(springSecurity()).build();
}
@WithMockUser(roles="ADMIN")
@Test
public void withMockUser() {
mvc.perform(get("......"))
}
}
答案2
得分: 0
切面导向的特性,比如 @PreAuthorize
,被实现为 advice。通常情况下,这意味着 Spring 会创建一个装饰器接口,拦截方法调用,执行相应的建议(在这种情况下,检查条件并在条件不满足时抛出异常),然后将调用发送到服务对象。
当你使用 new MyService
时,你创建了一个没有实现建议包装的裸对象,因此你不会看到安全性、验证、缓存等被应用。要看到你想要的行为,你需要使用 Spring 测试支持将你的测试bean设置为 @Autowired
。
英文:
Aspect-oriented features like @PreAuthorize
are implemented as advice. Usually, this means that Spring will create a decorator interface that intercepts the method call, performs the advice (in this case, checking the condition and throwing an exception if it fails), and then sends the call on to the service object.
When you use new MyService
, you're creating a bare object without the wrappers that implement the advice, so you won't see security, validation, caching, etc., applied. To see the behavior you want, you need to make your test bean @Autowired
using the Spring test support.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论