Spring 模拟SecurityContextHolder/验证始终返回null
我知道这个问题被问了很多,但也许我有一些特别的问题。我正在尝试对支持REST(而不是Spring MVC)的Spring引导应用程序进行一些集成测试,并且出于某种原因,Spring 模拟SecurityContextHolder/验证始终返回null,spring,spring-security,mockito,junit4,spring-test,Spring,Spring Security,Mockito,Junit4,Spring Test,我知道这个问题被问了很多,但也许我有一些特别的问题。我正在尝试对支持REST(而不是Spring MVC)的Spring引导应用程序进行一些集成测试,并且出于某种原因,SecurityContextHolder.getContext().getAuthentication()始终返回null,即使在测试中使用@WithMockUser。我不确定这是否与在配置类上使用概要文件有关,但到目前为止,我们还没有遇到过这方面的问题 等级 附加说明:这个Spring Boot应用程序也使用OAuth2进行授
SecurityContextHolder.getContext().getAuthentication()
始终返回null,即使在测试中使用@WithMockUser
。我不确定这是否与在配置类上使用概要文件有关,但到目前为止,我们还没有遇到过这方面的问题
等级
附加说明:这个Spring Boot应用程序也使用OAuth2进行授权,但在这些测试中必须关闭它。这就是为什么我们使用配置文件。省略@ActiveProfiles
注释会导致针对端点请求的错误
我可以使用PowerMock,但如果可能的话,我想避免使用它。我最终使用了
MockMvc
,尽管该应用程序不是基于Spring MVC的。此外,我将SecurityContext
调用分离到另一个服务中,但在此之前,我可以断言@WithMockUser
注释工作正常
这项工作的关键是在类级别使用以下代码段:
@WebMvcTest(MeController.class)
@Import({ControllerConfiguration.class, BeanConfiguration.class})
public class MeControllerTest {
// ...
}
使用
@WebMvcTest
有助于不必首先初始化SecurityContext
。您甚至不必调用springSecurity()
。您只需像往常一样执行mockMvc.perform()
操作,对SecurityContext
的任何调用都将返回您指定的模拟用户,使用@WithMockUser
或模拟处理此类调用的服务。编写Junit用于身份验证SecurityContextHolder的更简单方法是模拟它们。以下是它的工作实现。
您可以根据需要添加模拟类,然后设置SecurityContextHolder的上下文,然后使用when()进一步模拟并返回适当的模拟值
AccessToken mockAccessToken = mock(AccessToken.class);
Authentication authentication = mock(Authentication.class);
SecurityContext securityContext = mock(SecurityContext.class);
when(securityContext.getAuthentication()).thenReturn(authentication);
SecurityContextHolder.setContext(securityContext);
when(SecurityContextHolder.getContext().getAuthentication().getDetails()).thenReturn(mockSimpleUserObject);
这个示例代码适用于我。此代码正在使用JUnit 5
@SpringBootTest(class=Application.class)
@AutoConfigureMockMvc//在Spring引导测试中需要这个
公共类LoginControllerIntegrationTest{
//mockMvc不是@Autowired,因为我在@beforeach@之前自定义它
私有MockMvc-MockMvc;
@自动连线
私有WebApplicationContext上下文;
@嘲弄
客户负责人;
@之前
每个()之前的公共无效{
Authentication=mock(OAuth2AuthenticationToken.class);
//用于授权对象的Mockito.whens()
SecurityContext SecurityContext=mock(SecurityContext.class);
当(securityContext.getAuthentication())。然后返回(身份验证);
when(authentication.getPrincipal())。然后返回(principal);
setContext(securityContext);
//使用自定义securityContext设置mockMvc
this.mockMvc=MockMvcBuilders.webAppContextSetup(this.context.build();
}
@试验
public void在登录时为\u提供任何\u OAuth2AuthenticationToken\u,然后将\u重定向到\u logout()引发异常{
最终字符串loginName=“admin”;
//给定
//根据需要操纵委托人
when(principal.getAttribute(“unique_name”)).thenReturn(loginName);
//@formatter:off
//什么时候
this.mockMvc.perform(get(“/login”))
.andDo(print())
//然后
.andExpect(状态().isFound())
.andExpect(重定向到URL(“/注销”);
//@formatter:off
}
}
您实际上不必模拟SecurityContext和身份验证。尝试创建真实对象并设置为SecurityContextHolder。好吧。。。尝试在@Before
方法上设置SecurityContextHolder.createEmptyContext()
,但无效。还尝试了:@Before@Override public void resetMocks(){SecurityContextImpl securityContext=new SecurityContextImpl();securityContext.setAuthentication(新用户名PasswordAuthenticationToken(“user”,null));SecurityContextHolder.setContext(securityContext);reset(employeeRepository);}
仍将主体设置为null…很抱歉,我不清楚这一点。当我需要模拟两个不同的用户时,我应该如何传递模拟的访问令牌?
org.springframework.beans.factory.BeanCreationException: Could not inject field: private org.springframework.security.core.Authentication com.gft.employee.controller.MeControllerTest.authentication; nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'org.springframework.security.core.Authentication#0' is expected to be of type 'org.springframework.security.core.Authentication' but was actually of type '$java.security.Principal$$EnhancerByMockitoWithCGLIB$$657040e6'
@WebMvcTest(MeController.class)
@Import({ControllerConfiguration.class, BeanConfiguration.class})
public class MeControllerTest {
// ...
}
AccessToken mockAccessToken = mock(AccessToken.class);
Authentication authentication = mock(Authentication.class);
SecurityContext securityContext = mock(SecurityContext.class);
when(securityContext.getAuthentication()).thenReturn(authentication);
SecurityContextHolder.setContext(securityContext);
when(SecurityContextHolder.getContext().getAuthentication().getDetails()).thenReturn(mockSimpleUserObject);