问题描述
我正在尝试运行简单的单元测试,以正确的方式配置了Keycloak(我对其进行了测试,并且我的mvc应用正在连接并且用户已通过身份验证_,但现在我尝试对我的控制器进行测试,即使我用了spring slices keycloak适配器被调用并给我错误.适配器配置主要来自keycloak文档
I'm trying to run simple unit test, Keycloak is configured in proper way( I tested it and my mvc app is connecting and users are authenticated_ but now I tried to test my controllers and even thoughI used spring slices keycloak adapter is invoked and giving me errors. Adapter configuration is mostly brought from keycloak documentation
@WebMvcTest(UserController.class)
class UserControllerTest {
@MockBean
UserService userService;
@Autowired
MockMvc mockMvc;
@BeforeEach
void setUp() {
}
@AfterEach
void tearDown() {
reset(userService);
}
@Test
void logout() throws Exception {
mockMvc.perform(get("/logout"))
.andExpect(status().isOk());
}
}
但是尝试运行它时出现错误,堆栈跟踪:
but I've got errors when I try to run it, stack trace:
java.lang.NullPointerException
at org.keycloak.adapters.KeycloakDeploymentBuilder.internalBuild(KeycloakDeploymentBuilder.java:57)
at org.keycloak.adapters.KeycloakDeploymentBuilder.build(KeycloakDeploymentBuilder.java:205)
at org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver.resolve(KeycloakSpringBootConfigResolver.java:37)
at org.keycloak.adapters.springsecurity.config.KeycloakSpringConfigResolverWrapper.resolve(KeycloakSpringConfigResolverWrapper.java:40)
at org.keycloak.adapters.AdapterDeploymentContext.resolveDeployment(AdapterDeploymentContext.java:89)
at org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter.doFilter(KeycloakPreAuthActionsFilter.java:81)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:74)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:133)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:133)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:133)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:133)
at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:182)
at org.czekalski.userkeycloak.controller.UserControllerTest.logout(UserControllerTest.java:50)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:532)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:115)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:171)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:167)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:114)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:59)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$4(NodeTestTask.java:108)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:98)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:74)
at java.util.ArrayList.forEach(ArrayList.java:1257)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$4(NodeTestTask.java:112)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:98)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:74)
at java.util.ArrayList.forEach(ArrayList.java:1257)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$4(NodeTestTask.java:112)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:98)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:74)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:220)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:188)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:202)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:181)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:74)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
添加到secTest.properties中的测试@TestPropertySource("classpath:secTest.properties")
中keycloak.enabled = false
没有帮助
adding to test @TestPropertySource("classpath:secTest.properties")
where inside secTest.propertieskeycloak.enabled = false
didn't help
正在测试的代码:
@Controller
public class UserController {
private final UserService userService;
public UserController( UserService userService) {
this.userService = userService;
}
@GetMapping("/index")
public String logout(){
return "users/logout";
}
@GetMapping("/logged")
public String loggedIn(Model model){
model.addAttribute("token", userService.getloggedInUser());
return "users/logged";
}
推荐答案
我刚刚写了一组库简化安全的Spring应用程序的单元测试.
它包括一个@WithMockKeycloackAuth
批注,以及Keycloak专用的MockMvc
请求后处理器和WebTestClient
配置器/增变器
It includes a @WithMockKeycloackAuth
annotation, along with Keycloak dedicated MockMvc
request post-processor and WebTestClient
configurer / mutator
样品用量:
@RunWith(SpringRunner.class)
@WebMvcTest(GreetingController.class)
@ContextConfiguration(classes = GreetingApp.class)
@ComponentScan(basePackageClasses = { KeycloakSecurityComponents.class, KeycloakSpringBootConfigResolver.class })
public class GreetingControllerTests extends ServletUnitTestingSupport {
@MockBean
MessageService messageService;
@Test
@WithMockKeycloackAuth
public void whenUserIsNotGrantedWithAuthorizedPersonelThenSecretRouteIsNotAccessible() throws Exception {
mockMvc().get("/secured-route").andExpect(status().isForbidden());
}
@Test
@WithMockKeycloackAuth("AUTHORIZED_PERSONNEL")
public void whenUserIsGrantedWithAuthorizedPersonelThenSecretRouteIsAccessible() throws Exception {
mockMvc().get("/secured-route").andExpect(content().string(is("secret route")));
}
@Test
@WithMockKeycloakAuth(
authorities = { "USER", "AUTHORIZED_PERSONNEL" },
id = @IdTokenClaims(sub = "42"),
oidc = @OidcStandardClaims(
email = "[email protected]",
emailVerified = true,
nickName = "Tonton-Pirate",
preferredUsername = "ch4mpy"),
privateClaims = @ClaimSet(stringClaims = @StringClaim(name = "foo", value = "bar")))
public void whenAuthenticatedWithKeycloakAuthenticationTokenThenCanGreet() throws Exception {
mockMvc().get("/greet")
.andExpect(status().isOk())
.andExpect(content().string(startsWith("Hello ch4mpy! You are granted with ")))
.andExpect(content().string(containsString("AUTHORIZED_PERSONNEL")))
.andExpect(content().string(containsString("USER")));
取决于我建议您使用的工具数量,可能会从maven-central获得spring-security-oauth2-test-addons
或spring-security-oauth2-test-webmvc-addons
:
Depending of how much of the tooling I propose you wish to you might get spring-security-oauth2-test-addons
or spring-security-oauth2-test-webmvc-addons
from maven-central:
<dependency>
<groupId>com.c4-soft.springaddons</groupId>
<artifactId>spring-security-oauth2-test-addons</artifactId>
<version>2.3.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.c4-soft.springaddons</groupId>
<artifactId>spring-security-oauth2-test-webmvc-addons</artifactId>
<version>2.3.4</version>
<scope>test</scope>
</dependency>
如果仅对@WithMockKeycloakAuth
注释感兴趣,那么
首先就足够了.第二种添加流畅的API(MockMvc请求后处理器)和其他内容,例如MockMvc包装器,其内容类型&的默认值为接受标题
First is enough if you're only interested in @WithMockKeycloakAuth
annotation. Second adds fluent API (MockMvc request post-processor) and other stuff like MockMvc wrapper with default values for content-type & accept headers
这篇关于使用密钥斗篷进行Springboot测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!