Spring Security Test和MockMvc为REST控制器

时间:2015-10-23 04:14:10

标签: spring-mvc spring-security spring-test-mvc spring-security-test

我正在尝试编写一个集成测试,该测试可以访问REST端点并获取特定经过身份验证的用户(我在测试中设置的用户)的数据。我最初使用mockMvc = webAppContextSetup(wac).apply(springSecurity()).build()尝试了我的设置,但这始终是BeanInstantiationException失败的。在Testing Spring Security and MvcMock using a custom UserDetails implementation的帮助下,我能够通过切换我的setUp来克服这个问题。现在,我已将设置切换为使用standaloneSetup,我可以调用我的控制器。但是,无论我做什么,我都无法获得我在我的测试中创建的自定义UserDetails对象,该对象在我的控制器中对MockMvc的调用结束了。

我使用的是Spring 4.2.2和Spring Security 4.0.1。

我的测试代码如下所示:

import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { RestControllerITConfig.class })
@WebAppConfiguration
public class ControllerIT {

  private MockMvc mockMvc;

  @Before
  public void setUp() {
    mockMvc = standaloneSetup(new Controller())
                .setCustomArgumentResolvers(new AuthenticationPrincipalArgumentResolver())
                .build();
  }

  @Test
  public void testGetEndpoint() throws Exception {
    CustomUserDetails userDetails = new CustomUserDetails("John","Smith", "abc123");
    assertNotNull(userDetails);
    MvcResult result = mockMvc.perform(
      get("/somepath").with(user(userDetails)))    
      .andExpect(status().isOk())
      .andExpect(content().contentType("text/json")));
  }
}

@Configuration
@ComponentScan(basePackageClasses = { AuthenticationConfig.class })
public class RestControllerITConfig {
}

@Configuration
@EnableWebSecurity
@ComponentScan("com.my.authentication.package")
public class AuthenticationConfig extends WebSecurityConfigurerAdapter {
  // snip
}

@Target({ ElementType.PARAMETER, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@AuthenticationPrincipal
public @interface MyUser {
}

@RestController
@RequestMapping("/somepath")
public class Controller {

  @RequestMapping(value = "", method = RequestMethod.GET)
  public ResponseEntity<Object> getSomePath(@MyUser CustomUserDetails customUser) {
    customUser.getName(); // <== Causes NPE
  }
}

为简洁起见,还省略了其他一些不相关的配置。我真的不明白为什么我在测试中明确创建的自定义UserDetails对象没有传递到我的REST控制器,而是一个空对象。我在这做错了什么?有没有人有类似案例的工作示例?非常感谢提前。

2 个答案:

答案 0 :(得分:0)

我终于能够通过明确地将AuthenticationConfig的过滤器添加到StandaloneMockMvcBuilder来实现此功能。所以我的设置现在看起来像:

private MockMvc mockMvc;
@Autowired
private MyController controller;
@Autowired
private AuthenticationConfig authConfig;

@Before
public void setUp() {
  mockMvc = standaloneSetup(controller)
              .setCustomArgumentResolvers(new AuthenticationPrincipalArgumentResolver())
              .addFilters(authConfig.getCustomFilter())
              .build();
}

答案 1 :(得分:0)

如果您使用具有自定义用户详细信息实现的 Spring 5,则可以轻松使用 @WithUserDetails 注释

例如

@Test
@WithUserDetails
void createInstitution

您可以在 spring 安全文档 Spring security documentation

上找到详细信息