使用 Spring Security 进行单元测试

我的公司一直在评估Spring MVC,以确定我们是否应该在下一个项目中使用它。到目前为止,我喜欢我所看到的,现在我正在查看Spring Security模块,以确定它是否是我们可以/应该使用的东西。

我们的安全要求非常基本;用户只需要能够提供用户名和密码即可访问网站的某些部分(例如获取有关其帐户的信息);并且网站上有一些页面(常见问题解答,支持等),应该授予匿名用户访问权限。

在我一直在创建的原型中,我一直在会话中为经过身份验证的用户存储一个“LoginCredentials”对象(其中仅包含用户名和密码);例如,某些控制器会检查此对象是否在会话中,以获取对登录用户名的引用。我希望用Spring Security取代这种自制的逻辑,这将有一个很好的好处,即从我的控制器/业务代码中删除任何类型的“我们如何跟踪登录用户?”和“我们如何对用户进行身份验证”。

似乎Spring Security提供了一个(每个线程)“上下文”对象,以便能够从应用程序中的任何地方访问用户名/主体信息...

Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();

...这似乎非常不像春天,因为这个对象在某种程度上是一个(全局)单例。

我的问题是:如果这是在Spring Security中访问有关经过身份验证的用户的信息的标准方法,那么将身份验证对象注入SecurityContext以便当单元测试需要经过身份验证的用户时,它可用于我的单元测试的可接受方法是什么?

我是否需要在每个测试用例的初始化方法中将其连接起来?

protected void setUp() throws Exception {
    ...
    SecurityContextHolder.getContext().setAuthentication(
        new UsernamePasswordAuthenticationToken(testUser.getLogin(), testUser.getPassword()));
    ...
}

这似乎过于冗长。有没有更简单的方法?

物体本身看起来非常不像弹簧...SecurityContextHolder


答案 1

只需按照通常的方式进行操作,然后在测试类中使用将其插入,例如:SecurityContextHolder.setContext()

控制器:

Authentication a = SecurityContextHolder.getContext().getAuthentication();

测试:

Authentication authentication = Mockito.mock(Authentication.class);
// Mockito.whens() for your authorization object
SecurityContext securityContext = Mockito.mock(SecurityContext.class);
Mockito.when(securityContext.getAuthentication()).thenReturn(authentication);
SecurityContextHolder.setContext(securityContext);

答案 2

在不回答有关如何创建和注入身份验证对象的问题的情况下,Spring Security 4.0在测试方面提供了一些受欢迎的替代方案。注释使开发人员能够以简洁的方式指定模拟用户(具有可选的权限,用户名,密码和角色):@WithMockUser

@Test
@WithMockUser(username = "admin", authorities = { "ADMIN", "USER" })
public void getMessageWithMockUserCustomAuthorities() {
    String message = messageService.getMessage();
    ...
}

还有一个选项可用于模拟从 返回的 ,例如@WithUserDetailsUserDetailsUserDetailsService

@Test
@WithUserDetails("customUsername")
public void getMessageWithUserDetailsCustomUsername() {
    String message = messageService.getMessage();
    ...
}

更多细节可以在Spring Security参考文档(从中复制上述示例)中的@WithMockUser和@WithUserDetails章节中找到。