Keycloak:使用新创建的客户端和用户获取 JWT

Posted

技术标签:

【中文标题】Keycloak:使用新创建的客户端和用户获取 JWT【英文标题】:Keycloak: Obtain JWT Using Newly Created Client and User 【发布时间】:2021-06-21 17:44:17 【问题描述】:

使用Java 中的keycloak-admin-client,我成功地创建了一个新客户端和一个新用户。但是,我似乎无法使用用户为客户端获取 JWT。

这是我的代码:

        // Create a keycloak instance with admin privs
        Keycloak keycloak =
                KeycloakBuilder.builder()
                        .serverUrl("http://localhost:8080/auth")
                        .grantType(OAuth2Constants.PASSWORD)
                        .realm("master")
                        .username("admin")
                        .password("adminPass")
                        .clientId("admin-cli")
                        .resteasyClient(new ResteasyClientBuilderImpl().connectionPoolSize(10).build())
                        .build();

        // Edit: Create the realm "test-realm"
        RealmRepresentation realmRep = new RealmRepresentation();
        realmRep.setRealm("test-realm");
        realmRep.setEnabled(true);
        keycloak.realms().create(realmRep);

        // Create the client "test-client"
        ClientRepresentation clientRep = new ClientRepresentation();
        clientRep.setClientId("test-client");
        clientRep.setSecret(UUID.randomUUID().toString());
        clientRep.setProtocol("openid-connect");
        // ????❌ Edit: This is the current problem, I need the client to be confidential.
        clientRep.setBearerOnly(true);
        // ???? Edit: Added this but still getting 400
        clientRep.setDirectAccessGrantsEnabled(true);
        // ???? Edit: Added this and it fixed part of the problem
        clientRep.setEnabled(true);

        keycloak.realm("test-realm").clients().create(clientRep);

        // Create the user "test-user"
        CredentialRepresentation credRep = new CredentialRepresentation();
        credRep.setType(CredentialRepresentation.PASSWORD);
        credRep.setValue("test-user-pass");
        UserRepresentation userRep = new UserRepresentation();
        userRep.setUsername("test-user");
        userRep.setCredentials(Collections.singletonList(credRep));
        // ???? Edit: Added this and it fixed part of the problem
        userRep.setEnabled(true);

        keycloak.realm("test-realm").users().create(userRep);

        // Create another Keycloak instance with the new user's credentials
        keycloak =
                KeycloakBuilder.builder()
                        .serverUrl("http://localhost:8080/auth")
                        .grantType(OAuth2Constants.PASSWORD)
                        .realm("test-realm")
                        .username("test-user")
                        .password("test-user-pass")
                        .clientId("test-client")
                        .clientSecret(clientRep.getSecret())
                        .resteasyClient(new ResteasyClientBuilderImpl().connectionPoolSize(10).build())
                        .build();

        // Try and obtain a JWT
        AccessTokenResponse atr = keycloak.tokenManager().getAccessToken(); // ???? Fails with 400
        DecodedJWT jwt =  JWT.decode(atr.getToken());

这给了我一个javax.ws.rs.BadRequestException: HTTP 400 Bad Request,但不幸的是,我似乎找不到比这更有帮助的东西了。我已经调试过,但无法辨别任何可以告诉我我的请求到底有什么问题的消息。

我还尝试从创建客户端并将其传递给第二个 Keycloak 实例中删除客户端密码,但我仍然得到400

编辑:我已尝试查看日志(我在 Docker 容器中运行 Keycloak),但出现此问题时似乎没有记录任何内容。

编辑:我还为客户和用户添加了一个基本角色(没有任何权限,只是最基本的角色),但这仍然没有帮助。我希望这是一个角色/权限问题,但我会得到未经授权的,而不是400

编辑:原来我的部分问题是我的用户(和我的客户的问题)没有启用。启用两个固定部分的问题。我的最后一个问题是我需要客户端保密,但我找不到如何通过 Java 客户端 API 进行配置。

????目前我不知道如何将访问类型配置为对 Java 客户端保密。

【问题讨论】:

.grantType(OAuth2Constants.PASSWORD) 听起来您想使用直接访问授权流程,但我在您的 test-client (clientRep) 中看不到允许该流程。 好建议,但我试过了,但不幸的是我仍然收到400。我以后可能还需要它,所以我会保留它以防万一。 ***.com/questions/63721080/… 我发现了这个,我猜我可能需要创建一个新领域。如果我理解链接答案的问题,您将无法从 master 领域获得 JWT。 我尝试使用 master 以外的其他领域,并且有一个短暂的时刻我认为我走在正确的轨道上,但我错了,我仍然得到 400。是否出于同样的原因我不确定,但我会尽快更新我的代码 sn-p 以反映我目前所拥有的。 在创建领域时,您可以设置以下内容:\ realmRep.eventsEnabled(true); realmRep.setEnabledEventTypes(List.of("LOGIN_ERROR","CODE_TO_TOKEN_ERROR","CLIENT_LOGIN_ERROR")); realmRep.setEventsExpiration(172800); 也许在管理 GUI 中会弹出一些事件来帮助您。 【参考方案1】:

好的,所以我的代码有多个问题。这些是我必须做的所有事情来解决我的问题:

    我必须创建一个新领域,而不是尝试从默认的master 领域获取 JWT 访问令牌。 Keycloak admin client responds with Bad Request to attempt to list realms 我的用户/客户端未启用。 clientRep.setEnabled(true); userRep.setEnabled(true); 我的客户是bearer-only,它只验证令牌,但不授予它们。 keycloak bearer-only clients: why do they exist? 可以使用public 客户端(默认)或使用clientRep.setPublicClient(false); 将其保密

【讨论】:

以上是关于Keycloak:使用新创建的客户端和用户获取 JWT的主要内容,如果未能解决你的问题,请参考以下文章

Keycloak:使用 keycloak-admin 为用户生成访问令牌

Keycloak 使用不同的客户端重新验证经过身份验证的用户

Keycloak 创建和修改自定义用户信息

如何从 Keycloak 获取用户 ID 和用户 UUID/GUID?

在 Keycloak 中创建新用户期间未分配客户端角色

Python Keycloak 获取用户的角色和组