如何对由 keycloak 保护的 SpringBoot 控制器进行单元测试?

Ant*_*ado 6 java spring-boot keycloak

我知道,关于这个问题,这里这里已经有类似的问题,但提出的每个解决方案都未能帮助我。大多数答案中也提到了这个库,但是(恕我直言)我想避免依赖外部库只是为了能够测试一个简单的控制器。

因此,我有一个非常简单的 api,可以使用 keycloak 生成的不记名令牌进行访问,我想测试控制器。沿着这些思路:

@Test
@DisplayName("Should be ok")
@WithMockUser
void whenCalled_shouldBeOk() throws Exception {
    SecurityContext context = SecurityContextHolder.getContext();
    Authentication authentication = context.getAuthentication();
    mockMvc.perform(
        post("/api/url/something")
            .content("{}")
            .contentType(APPLICATION_JSON)
            .with(authentication(authentication))
    ).andExpect(status().isOk());
}
Run Code Online (Sandbox Code Playgroud)

问题是我总是会得到一个空指针异常,因为KeycloakDeploymentBuilder它缺少适配器配置。在我们的 SecurityConfig 中,我们扩展KeycloakWebSecurityConfigurerAdapter并执行应用程序工作所需的所有配置,但我未能在测试中模拟/绕过此过程。通常我会在测试中使用 @WithMockUser 注释找到解决此身份验证问题的方法(当不使用 keycloak 时),但这次不行。

没有办法模拟适配器或过滤进程来绕过这个问题吗?

我已经尝试了其他问题(图书馆除外)中回答的所有内容,但没有运气。如果您有任何可能有帮助的线索,或者至少为我指明了正确的方向(因为这可能是由于我缺乏对 Spring 安全性的了解),我将非常感激。

ch4*_*4mp 3

2023年更新

用于 Spring 的已弃用的 Keycloak 适配器(定义的位置KeycloakAuthenticationToken)与 spring-boot 3 不兼容。“在 Spring Boot 3 中使用 Keycloak Spring 适配器”的接受答案中的替代方案

原答案

正如我在对您链接的第一个问题的回答中所写的@WithMockUser那样,UsernamePaswordAuthenticationToken当您的代码/conf 可能需要KeycloakAuthenticationToken.

如果您仔细阅读相同的答案,您将找到使用我的库来执行此操作的替代方法:在每个测试中使用实例或模拟手动填充安全上下文 KeycloakAuthenticationToken

我添加到我的仓库中的 Mockito 的最小样本:

    @Test
    public void test() {
        final var principal = mock(Principal.class);
        when(principal.getName()).thenReturn("user");

        final var account = mock(OidcKeycloakAccount.class);
        when(account.getRoles()).thenReturn(Set.of("offline_access", "uma_authorization"));
        when(account.getPrincipal()).thenReturn(principal);

        final var authentication = mock(KeycloakAuthenticationToken.class);
        when(authentication.getAccount()).thenReturn(account);

        // post(...).with(authentication(authentication))
        // limits to testing secured @Controller with MockMvc
        // I prefer to set security context directly instead:
        SecurityContextHolder.getContext().setAuthentication(authentication);

        //TODO: invoque mockmvc to test @Controller or test any other type of @Component as usual
    }
Run Code Online (Sandbox Code Playgroud)

也许,在您确定这对您的测试造成了多大的混乱(这里设置的声明很少)之后,您会重新考虑使用我的库(或从它复制,因为它是开源的)。

经过我的注释,上面的示例变成:

    @Test
    @WithMockKeycloakAuth
    public void test() throws Exception {
        //TODO: invoque mockmvc to test @Controller or test any other type of @Component as usual
    }
Run Code Online (Sandbox Code Playgroud)

关于涉及Keycloak的spring测试配置,您可以深入研究一下spring-addons-keycloak模块的测试。您会发现一个使用单元测试(和工作测试配置)的完整应用程序。KeycloakAuthenticationToken

最后(可能是题外话)您可以阅读存储库主自述文件并考虑使用比 Keycloak 更通用的 OIDC 实现。我提供了一个以及测试注释,并编写了有关如何将其扩展以满足您的应用程序特定需求的教程。