You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Keycloak Admin Client 24.0.0开启客户端认证与授权?

Keycloak Admin Client 24.0.0 开启客户端认证与授权功能问题

我使用org.keycloak:keycloak-admin-client:24.0.0在Keycloak 24.0.0上通过代码创建领域和客户端,需要开启Client authentication和Authorization功能。

先创建客户端,再用以下代码更新配置:

ClientRepresentation clientRepresentation = getClientRepresentation(realm);
ClientResource clientResource = getClientResource(realm, clientRepresentation);
clientRepresentation.setAuthorizationServicesEnabled(true);
clientRepresentation.setStandardFlowEnabled(true);
clientRepresentation.setDirectAccessGrantsEnabled(true);
clientRepresentation.setPublicClient(true);
clientRepresentation.setEnabled(true);
clientRepresentation.setServiceAccountsEnabled(true);
clientRepresentation.setAlwaysDisplayInConsole(true);
clientRepresentation.setAttributes(Map.of(
    "oauth2.device.authorization.grant.enabled", "false",
    "oidc.ciba.grant.enabled", "false",
    "login_theme", "base",
    "display.on.consent.screen", "false",
    "backchannel.logout.url", "",
    "backchannel.logout.session.required", "true",
    "backchannel.logout.revoke.offline.tokens", "false"
));
clientRepresentation.setRedirectUris(List.of(publicUrl + "/*"));
clientResource.update(clientRepresentation);

调试时看到发送的PUT请求体如下:

{
    "id": "de890c6a-7695-4cce-b512-87989059860c",
    "clientId": "my-client",
    "name": "my-client",
    "description": null,
    "rootUrl": null,
    "adminUrl": null,
    "baseUrl": null,
    "surrogateAuthRequired": false,
    "enabled": true,
    "alwaysDisplayInConsole": true,
    "clientAuthenticatorType": "client-secret",
    "secret": null,
    "registrationAccessToken": null,
    "defaultRoles": null,
    "redirectUris": [
        "http://localhost:8080/*"
    ],
    "webOrigins": [],
    "notBefore": 0,
    "bearerOnly": false,
    "consentRequired": false,
    "standardFlowEnabled": true,
    "implicitFlowEnabled": false,
    "directAccessGrantsEnabled": true,
    "serviceAccountsEnabled": true,
    "authorizationServicesEnabled": true,
    "directGrantsOnly": null,
    "publicClient": true,
    "frontchannelLogout": false,
    "protocol": "openid-connect",
    "attributes": {
        "oidc.ciba.grant.enabled": "false",
        "client.secret.creation.time": "1709725705",
        "backchannel.logout.session.required": "true",
        "login_theme": "base",
        "display.on.consent.screen": "false",
        "oauth2.device.authorization.grant.enabled": "false",
        "backchannel.logout.revoke.offline.tokens": "false"
    },
    "authenticationFlowBindingOverrides": {},
    "fullScopeAllowed": true,
    "nodeReRegistrationTimeout": -1,
    "registeredNodes": null,
    "protocolMappers": [
        {
            "id": "a939828f-f524-4d06-aacf-490ea0e2e105",
            "name": "Client IP Address",
            "protocol": "openid-connect",
            "protocolMapper": "oidc-usersessionmodel-note-mapper",
            "consentRequired": false,
            "consentText": null,
            "config": {
                "user.session.note": "clientAddress",
                "introspection.token.claim": "true",
                "id.token.claim": "true",
                "access.token.claim": "true",
                "claim.name": "clientAddress",
                "jsonType.label": "String"
            }
        },
        {
            "id": "b62609d1-330f-445e-ab73-edf78b16f396",
            "name": "Client ID",
            "protocol": "openid-connect",
            "protocolMapper": "oidc-usersessionmodel-note-mapper",
            "consentRequired": false,
            "consentText": null,
            "config": {
                "user.session.note": "client_id",
                "introspection.token.claim": "true",
                "id.token.claim": "true",
                "access.token.claim": "true",
                "claim.name": "client_id",
                "jsonType.label": "String"
            }
        },
        {
            "id": "1d78e050-38eb-4da5-950e-fe5112471ddf",
            "name": "Client Host",
            "protocol": "openid-connect",
            "protocolMapper": "oidc-usersessionmodel-note-mapper",
            "consentRequired": false,
            "consentText": null,
            "config": {
                "user.session.note": "clientHost",
                "introspection.token.claim": "true",
                "id.token.claim": "true",
                "access.token.claim": "true",
                "claim.name": "clientHost",
                "jsonType.label": "String"
            }
        }
    ],
    "clientTemplate": null,
    "useTemplateConfig": null,
    "useTemplateScope": null,
    "useTemplateMappers": null,
    "defaultClientScopes": [
        "web-origins",
        "acr",
        "roles",
        "profile",
        "email"
    ],
    "optionalClientScopes": [
        "address",
        "phone",
        "offline_access",
        "microprofile-jwt"
    ],
    "authorizationSettings": null,
    "access": {
        "view": true,
        "configure": true,
        "manage": true
    },
    "origin": null
}

请求体中已包含"authorizationServicesEnabled": true,但管理控制台客户端设置页的Capability Config部分,Authorization功能仍未开启;且开启两个开关后会出现Credentials标签(包含Client Id and Secret认证器及密钥),但代码操作后没有该标签。对比UI创建相同设置客户端的请求payload,发现与上述一致,不清楚问题所在。

问题:如何通过代码复现在UI中开启Client authentication和Authorization两个开关的操作?


解决方案

1. 修正客户端认证(Client authentication)的配置

你当前设置了publicClient = true,这会将客户端标记为公开客户端,而公开客户端默认不启用客户端认证(对应UI的Client authentication开关关闭)。要开启该开关,需要:

  • 将publicClient设置为false
  • 确保clientAuthenticatorType设置为client-secret(默认值,显式指定更清晰)

2. 确保Authorization功能正确生效

仅设置authorizationServicesEnabled = true可能不足以让UI显示开启状态,Keycloak需要初始化授权设置才能激活UI开关并显示Authorization标签页,可通过两种方式处理:

方式一:创建客户端时直接初始化授权设置

在ClientRepresentation中添加授权配置对象:

AuthorizationSettingsRepresentation authSettings = new AuthorizationSettingsRepresentation();
clientRepresentation.setAuthorizationSettings(authSettings);

方式二:更新客户端后显式初始化授权配置

更新客户端后单独调用授权设置接口:

AuthorizationSettingsRepresentation authSettings = new AuthorizationSettingsRepresentation();
clientResource.authorization().getSettings().update(authSettings);

3. 完整修正后的代码示例

ClientRepresentation clientRepresentation = getClientRepresentation(realm);
ClientResource clientResource = getClientResource(realm, clientRepresentation);

// 开启Client authentication:设置为保密客户端
clientRepresentation.setPublicClient(false);
clientRepresentation.setClientAuthenticatorType("client-secret");

// 开启Authorization并初始化配置
clientRepresentation.setAuthorizationServicesEnabled(true);
AuthorizationSettingsRepresentation authSettings = new AuthorizationSettingsRepresentation();
clientRepresentation.setAuthorizationSettings(authSettings);

// 原有配置保留
clientRepresentation.setStandardFlowEnabled(true);
clientRepresentation.setDirectAccessGrantsEnabled(true);
clientRepresentation.setEnabled(true);
clientRepresentation.setServiceAccountsEnabled(true);
clientRepresentation.setAlwaysDisplayInConsole(true);
clientRepresentation.setAttributes(Map.of(
    "oauth2.device.authorization.grant.enabled", "false",
    "oidc.ciba.grant.enabled", "false",
    "login_theme", "base",
    "display.on.consent.screen", "false",
    "backchannel.logout.url", "",
    "backchannel.logout.session.required", "true",
    "backchannel.logout.revoke.offline.tokens", "false"
));
clientRepresentation.setRedirectUris(List.of(publicUrl + "/*"));

// 更新客户端
clientResource.update(clientRepresentation);

// 可选:若授权未生效,单独更新授权配置
// clientResource.authorization().getSettings().update(authSettings);

关键说明

  • Client authentication开关:仅保密客户端(publicClient = false)能开启该功能,公开客户端无需密钥认证,因此UI开关默认关闭。
  • Authorization开关:必须初始化授权设置(哪怕是默认配置),Keycloak才会在UI中激活该开关并显示Authorization标签页。
  • Credentials标签:当客户端为保密类型且认证器为client-secret时,Keycloak会自动生成客户端密钥,Credentials标签会自动出现。

内容的提问来源于stack exchange,提问作者ndtreviv

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 19:37:02