Spring 安全测试和 MockMvc 向 REST 控制器提供空自定义 UserDetails 参数
Spring Security Test and MockMvc supply null custom UserDetails parameter to REST Controller
我正在尝试编写一个集成测试,该测试命中 REST 端点并为特定的经过身份验证的用户(我在测试中设置的用户)获取数据。我最初尝试使用 mockMvc = webAppContextSetup(wac).apply(springSecurity()).build()
进行设置,但始终因 BeanInstantiationException
而失败。在 Testing Spring Security and MvcMock using a custom UserDetails implementation 的帮助下,我能够通过切换我的设置来克服这个问题。现在我已经将我的设置切换为使用 standaloneSetup
,我可以调用我的控制器。但是,无论我做什么,我都无法将我在测试中创建的自定义 UserDetails 对象获取到控制器中对 MockMvc 的调用结束的方法中。
我正在使用 Spring 4.2.2 和 Spring 安全 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 控制器中,而是一个空对象。我在这里做错了什么?有没有人有类似案例的工作示例?非常感谢。
我终于能够通过将我的 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();
}
如果您将 Spring 5 与自定义用户详细信息实现一起使用,则可以轻松使用 @WithUserDetails 注释
例如
@Test
@WithUserDetails
void createInstitution
您可以在 spring 安全文档中找到详细信息 Spring security documentation
我正在尝试编写一个集成测试,该测试命中 REST 端点并为特定的经过身份验证的用户(我在测试中设置的用户)获取数据。我最初尝试使用 mockMvc = webAppContextSetup(wac).apply(springSecurity()).build()
进行设置,但始终因 BeanInstantiationException
而失败。在 Testing Spring Security and MvcMock using a custom UserDetails implementation 的帮助下,我能够通过切换我的设置来克服这个问题。现在我已经将我的设置切换为使用 standaloneSetup
,我可以调用我的控制器。但是,无论我做什么,我都无法将我在测试中创建的自定义 UserDetails 对象获取到控制器中对 MockMvc 的调用结束的方法中。
我正在使用 Spring 4.2.2 和 Spring 安全 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 控制器中,而是一个空对象。我在这里做错了什么?有没有人有类似案例的工作示例?非常感谢。
我终于能够通过将我的 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();
}
如果您将 Spring 5 与自定义用户详细信息实现一起使用,则可以轻松使用 @WithUserDetails 注释
例如
@Test
@WithUserDetails
void createInstitution
您可以在 spring 安全文档中找到详细信息 Spring security documentation