我无法将我传递到mockmvc get请求的用户关联到安全上下文持有者,因此我无法创建一个模拟原则。
@Import(SecurityConfig::class)
@WebMvcTest(controllers = [MovieController::class])
class MovieControllerTests {
private lateinit var mockMvc: MockMvc
@MockBean
private lateinit var accountRepository: AccountRepository
@MockBean
private lateinit var movieRepository: MovieRepository
@BeforeEach
fun setup() {
mockMvc = MockMvcBuilders.standaloneSetup(MovieController(movieRepository, accountRepository))
.apply<StandaloneMockMvcBuilder?>(SecurityMockMvcConfigurers.springSecurity()).build()
}
@Test
fun `does return movie queue`() {
mockMvc.get("/movies/fetch-queue") {
with(user("donna"))
}.andExpectAll {
status {
isOk()
}
content {
contentType(MediaType.APPLICATION_JSON)
}
}
Mockito.verify(accountRepository).findAccountByUsername("donna")
}
}
我已阅读文档,说我需要手动将 securitycontextpersistencefilter 添加到mockmvc 实例,但我不知道具体该怎么做。该文档还指出,模拟用户只能通过将用户与 HttpServletRequest 关联来起作用。
在测试中修改SecurityContext的最简单方法是使用@WithMockUser。该注解允许您直接设置用户名、角色和权限。
@Test
@WithMockUser(username = "testuser", roles = {"USER"})
public void testWithMockUser() {
// Test code here
}
使用@WithSecurityContext创建自定义安全上下文如果您需要更高级的自定义(例如,设置特定的身份验证详细信息),您可以创建自定义注释并实现SecurityContextFactory。
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@WithSecurityContext(factory = CustomSecurityContextFactory.class)
public @interface WithCustomUser {
String username() default "customuser";
String[] roles() default {"USER"};
}
实现安全上下文工厂
public class CustomSecurityContextFactory implements WithSecurityContextFactory<WithCustomUser> {
@Override
public SecurityContext createSecurityContext(WithCustomUser customUser) {
SecurityContext context = SecurityContextHolder.createEmptyContext();
List<GrantedAuthority> authorities = Arrays.stream(customUser.roles())
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
Authentication auth = new UsernamePasswordAuthenticationToken(
customUser.username(), "password", authorities);
context.setAuthentication(auth);
return context;
}
}
事实上,Spring Security 使用基于 ThreadLocal 的 SecurityContextHolder 在测试和运行时存储和检索 SecurityContext。此方法可确保安全上下文的范围仅限于当前线程。想了解更多详情请看这里
org.springframework.security.test.context.TestSecurityContextHolder
Spring Security 中的这种 ThreadLocal 策略仅限于高级用例,例如将安全上下文传播到子线程或处理反应性和异步场景;但是,InheritableThreadLocal 或自定义策略等替代方案可以解决这些限制。