Spring Security Test and MockMvc supply null custom UserDetails parameter to REST Controller

点点圈 提交于 2019-12-06 10:51:41

问题


I'm trying to write an integration test that hits a REST endpoint and gets data for a specific authenticated user (the one I'm setting up in the test). I initially tried my setup with mockMvc = webAppContextSetup(wac).apply(springSecurity()).build(), but that was consistently failing with a BeanInstantiationException. With the help of Testing Spring Security and MvcMock using a custom UserDetails implementation, I was able to overcome that issue by switching up my setUp. Now that I've switched my setup to use standaloneSetup, I'm able to call into my controller. But, no matter what I do, I'm unable to get the custom UserDetails object that I'm creating in my test into the method in my controller that the call to MockMvc ends up at.

I'm using Spring 4.2.2 and Spring Security 4.0.1.

My test code looks something like this:

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
  }
}

There are other pieces of irrelevant configuration that have been omitted for the sake of brevity. I really don't understand why the custom UserDetails object that I'm explicit creating in the test isn't getting passed into my REST controller, but rather a null object is. What am I doing wrong here? Does anyone have a working example of a similar case? Many thanks in advance.


回答1:


I was finally able to get this to work by explicitly adding my AuthenticationConfig's filter onto the StandaloneMockMvcBuilder. So my setup now looks like:

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();
}


来源:https://stackoverflow.com/questions/33294769/spring-security-test-and-mockmvc-supply-null-custom-userdetails-parameter-to-res

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!