如何JUnit测试@PreAuthorize注释及其由spring MVC控制器指定的spring EL?

Posted

技术标签:

【中文标题】如何JUnit测试@PreAuthorize注释及其由spring MVC控制器指定的spring EL?【英文标题】:How to JUnit tests a @PreAuthorize annotation and its spring EL specified by a spring MVC Controller? 【发布时间】:2011-07-21 04:51:20 【问题描述】:

我已经在我的 Spring MVC 控制器中定义了这个方法:

@RequestMapping(value = "id/content", method=RequestMethod.POST)
@PreAuthorize("principal.user.userAccount instanceof T(com.anonym.model.identity.PedagoAccount) AND principal.user.userAccount.userId == #object.pedago.userId AND #form.id == #object.id")
public String modifyContent(@PathVariable("id") Project object, @Valid  @ModelAttribute("form") ProjectContentForm form) 
    ....

然后在我的 JUnit 测试中我想调用这个方法并确保 PreAuthorize 条件得到验证。但是,当我在我的 JUnit 测试中使用错误帐户设置用户主体时,没有错误并且该方法完成。看来注释被绕过了。 但是当我以正常方式(不是测试)调用这个方法时,PreAuthorize 被验证了。

如果可能的话,如何在junit测试中测试这个注解以及如果它抛出一个异常如何捕获?

谢谢, 尼古拉斯

【问题讨论】:

只是给在 PreAuthorize 中使用“principal”的其他人的注释,这将失败并返回 nullpointerexcpetion,并且不会触发重新授权,除非您在 PreAuthorize 注释中包含具有 isAuthenticated() 效果的内容或在security.xml中 【参考方案1】:

由于您想测试通过 Spring AOP 实现的功能,因此您需要使用 Spring TestContext 框架针对应用程序上下文运行测试。

然后您创建一个具有最少安全配置的基础测试:

abstract-security-test.xml:

<security:authentication-manager alias="authenticationManager">
    <security:authentication-provider user-service-ref = "userService" />
</security:authentication-manager>

<security:global-method-security pre-post-annotations="enabled" />

<bean id = "userService" class = "..." />

AbstractSecurityTest.java:

@ContextConfiguration("abstract-security-test.xml")
abstract public class AbstractSecurityTest 
    @Autowired
    private AuthenticationManager am;

    @After
    public void clear() 
        SecurityContextHolder.clearContext();
    

    protected void login(String name, String password) 
        Authentication auth = new UsernamePasswordAuthenticationToken(name, password);
        SecurityContextHolder.getContext().setAuthentication(am.authenticate(auth));
    

现在您可以在测试中使用它了:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(...)
public class CreatePostControllerSecurityTest extends AbstractSecurityTest 
    ...

    @Test
    @ExpectedException(AuthenticationCredentialsNotFoundException.class)
    public void testNoAuth() 
        controller.modifyContent(...);
    

    @Test
    @ExpectedException(AccessDeniedException.class)
    public void testAccessDenied() 
        login("userWithoutAccessRight", "...");
        controller.modifyContent(...);
    

    @Test
    public void testAuthOK() 
        login("userWithAccessRight", "...");
        controller.modifyContent(...);
    

【讨论】:

谢谢,它可以很好地进行身份验证,但是如果想测试 PreAuthorize 注释中定义的整个 Spring EL,我该怎么办? 谢谢,它可以很好地进行身份验证,但是如果我想测试 PreAuthorize 注释中定义的整个 Spring EL,我该怎么做?我的意思是如何验证 principal.user.userAccount.userId == #object.pedago.userId AND #form.id == #object.id 其中 #object 和 #form 指定 modifyContent 方法的变量。对于未经验证的安全 Spring EL 是否有任何异常需要捕获? @ExpectedException 注释已弃用;改用 JUnit4 的 @Test(expected=...)。 很好的建议。这对我来说非常有效。我做的一件有点不同的事情是,我将现有的security-context.xml 从我的webapp-context.xml 中分离出来,这样我就可以在我的测试中使用安全上下文配置,而不包括 Web 应用程序的东西。这样我就可以在我的测试中重用现有的安全配置。

以上是关于如何JUnit测试@PreAuthorize注释及其由spring MVC控制器指定的spring EL?的主要内容,如果未能解决你的问题,请参考以下文章

使用自定义 bean 测试 PreAuthorize 注释

如何对 Spring Security @PreAuthorize(hasRole) 进行单元测试?

如何在@PreAuthorize注释中传递调用自定义方法的spring句柄

如何在使用 @RunWith 和 @ContextConfiguration 注释的 jUnit 测试中访问 Spring 上下文?

如何使用 JUnit Test 注释断言我的异常消息?

如何等待@JMSListener注释方法在JUnit中完成