Keycloak 授权客户端

使用 Keycloak 授权客户端管理和检查权限

根据您的需求,资源服务器应该能够远程管理资源,甚至以编程方式检查权限。如果您使用 Java,可以使用授权客户端 API 访问 Keycloak 授权服务。

它针对的是希望访问服务器提供的不同端点的资源服务器,例如令牌端点、资源和权限管理端点。

Maven 依赖项

<dependencies>
    <dependency>
        <groupId>org.keycloak</groupId>
        <artifactId>keycloak-authz-client</artifactId>
        <version>26.0.2</version>
    </dependency>
</dependencies>

配置

客户端配置在 keycloak.json 文件中定义,如下所示

{
  "realm": "hello-world-authz",
  "auth-server-url" : "http://127.0.0.1:8080",
  "resource" : "hello-world-authz-service",
  "credentials": {
    "secret": "secret"
  }
}
  • realm (必需)

    域的名称。

  • auth-server-url (必需)

    Keycloak 服务器的基地址。所有其他 Keycloak 页面和 REST 服务端点都由此派生。它通常采用以下形式 https://host:port.

  • resource (必需)

    应用程序的客户端 ID。每个应用程序都有一个用于标识应用程序的客户端 ID。

  • credentials (必需)

    指定应用程序的凭据。这是一个对象表示法,其中键是凭据类型,值是凭据类型的值。详细信息请参见 专用部分

配置文件通常位于应用程序的类路径中,这是客户端尝试查找 keycloak.json 文件的默认位置。

创建授权客户端

考虑到您在类路径中有一个 keycloak.json 文件,您可以创建一个新的 AuthzClient 实例,如下所示

// create a new instance based on the configuration defined in a keycloak.json located in your classpath
AuthzClient authzClient = AuthzClient.create();

获取用户授权

以下是一个说明如何获取用户授权的示例

// create a new instance based on the configuration defined in keycloak.json
AuthzClient authzClient = AuthzClient.create();

// create an authorization request
AuthorizationRequest request = new AuthorizationRequest();

// send the entitlement request to the server in order to
// obtain an RPT with all permissions granted to the user
AuthorizationResponse response = authzClient.authorization("alice", "alice").authorize(request);
String rpt = response.getToken();

System.out.println("You got an RPT: " + rpt);

// now you can use the RPT to access protected resources on the resource server

以下是一个说明如何为一组一个或多个资源获取用户授权的示例

// create a new instance based on the configuration defined in keycloak.json
AuthzClient authzClient = AuthzClient.create();

// create an authorization request
AuthorizationRequest request = new AuthorizationRequest();

// add permissions to the request based on the resources and scopes you want to check access
request.addPermission("Default Resource");

// send the entitlement request to the server in order to
// obtain an RPT with permissions for a single resource
AuthorizationResponse response = authzClient.authorization("alice", "alice").authorize(request);
String rpt = response.getToken();

System.out.println("You got an RPT: " + rpt);

// now you can use the RPT to access protected resources on the resource server

使用保护 API 创建资源

// create a new instance based on the configuration defined in keycloak.json
AuthzClient authzClient = AuthzClient.create();

// create a new resource representation with the information we want
ResourceRepresentation newResource = new ResourceRepresentation();

newResource.setName("New Resource");
newResource.setType("urn:hello-world-authz:resources:example");

newResource.addScope(new ScopeRepresentation("urn:hello-world-authz:scopes:view"));

ProtectedResource resourceClient = authzClient.protection().resource();
ResourceRepresentation existingResource = resourceClient.findByName(newResource.getName());

if (existingResource != null) {
    resourceClient.delete(existingResource.getId());
}

// create the resource on the server
ResourceRepresentation response = resourceClient.create(newResource);
String resourceId = response.getId();

// query the resource using its newly generated id
ResourceRepresentation resource = resourceClient.findById(resourceId);

System.out.println(resource);

对 RPT 进行反向解析

// create a new instance based on the configuration defined in keycloak.json
AuthzClient authzClient = AuthzClient.create();

// send the authorization request to the server in order to
// obtain an RPT with all permissions granted to the user
AuthorizationResponse response = authzClient.authorization("alice", "alice").authorize();
String rpt = response.getToken();

// introspect the token
TokenIntrospectionResponse requestingPartyToken = authzClient.protection().introspectRequestingPartyToken(rpt);

System.out.println("Token status is: " + requestingPartyToken.getActive());
System.out.println("Permissions granted by the server: ");

for (Permission granted : requestingPartyToken.getPermissions()) {
    System.out.println(granted);
}

客户端身份验证

当授权客户端需要发送反向通道请求时,它需要对 Keycloak 服务器进行身份验证。默认情况下,有三种方法可以对客户端进行身份验证:客户端 ID 和客户端密钥、使用签署的 JWT 进行客户端身份验证,或者使用客户端密钥使用签署的 JWT 进行客户端身份验证。

客户端 ID 和客户端密钥

这是 OAuth2 规范中描述的传统方法。客户端有一个密钥,该密钥需要由客户端和 Keycloak 服务器同时知道。您可以在 Keycloak 管理控制台中为特定客户端生成密钥,然后将此密钥粘贴到应用程序端的 keycloak.json 文件中

"credentials": {
    "secret": "19666a4f-32dd-4049-b082-684c74115f28"
}

使用签署的 JWT 进行客户端身份验证

这是基于 RFC7523 规范的。它的工作原理如下

  • 客户端必须拥有私钥和证书。对于授权客户端,这可以通过传统的 keystore 文件获得,该文件要么位于客户端应用程序的类路径中,要么位于文件系统的某个位置。

  • 在身份验证期间,客户端生成一个 JWT 令牌,并使用其私钥对其进行签名,并将该令牌发送到 Keycloak 中的 client_assertion 参数中的特定请求中。

  • Keycloak 必须拥有客户端的公钥或证书,以便它可以验证 JWT 上的签名。在 Keycloak 中,您可以为客户端配置客户端凭据。首先,您在管理控制台的“凭据”选项卡中选择“签署的 JWT”作为身份验证客户端的方法。然后,您可以在“密钥”选项卡中选择以下方法之一

    • 配置 JWKS URL,Keycloak 可以从中下载客户端的公钥。此选项最灵活,因为客户端可以随时轮换其密钥,Keycloak 始终根据需要下载新密钥,而无需更改配置。换句话说,当 Keycloak 看到由未知 kid(密钥 ID)签名的令牌时,它会下载新密钥。但是,您需要负责将公钥以 JWKS 格式公开,以便服务器可以使用它。

    • 上传客户端的公钥或证书,可以是 PEM 格式、JWK 格式,也可以来自密钥库。使用此选项,公钥是硬编码的,并且在客户端生成新的密钥对时必须更改。如果您没有自己的密钥库可用,您甚至可以在 Keycloak 管理控制台中生成自己的密钥库。当使用授权客户端时,此选项最简单。

要为此方法进行设置,您需要在 keycloak.json 文件中编写类似以下内容

"credentials": {
  "jwt": {
    "client-keystore-file": "classpath:keystore-client.jks",
    "client-keystore-type": "JKS",
    "client-keystore-password": "storepass",
    "client-key-password": "keypass",
    "client-key-alias": "clientkey",
    "token-expiration": 10
  }
}

使用此配置,密钥库文件 keystore-client.jks 必须位于使用授权客户端的应用程序的类路径中。如果您不使用前缀 classpath:,则可以指向客户端应用程序运行的任何文件系统上的文件。

使用客户端密钥使用签署的 JWT 进行客户端身份验证

这与使用签署的 JWT 进行客户端身份验证相同,只是使用客户端密钥而不是私钥和证书。

客户端有一个密钥,该密钥需要由使用授权客户端的应用程序和 Keycloak 服务器同时知道。您在管理控制台的“凭据”选项卡中选择“使用客户端密钥签署的 JWT”作为身份验证客户端的方法,然后将此密钥粘贴到应用程序端的 keycloak.json 文件中

"credentials": {
  "secret-jwt": {
    "secret": "19666a4f-32dd-4049-b082-684c74115f28",
    "algorithm": "HS512"
  }
}

“算法”字段指定使用客户端密钥签署的 JWT 的算法。它需要是以下值之一:HS256、HS384 和 HS512。有关详细信息,请参见 JSON Web 算法 (JWA)

此“算法”字段是可选的;如果 keycloak.json 文件中不存在“算法”字段,则会自动应用 HS256。

添加您自己的客户端身份验证方法

您也可以添加您自己的客户端身份验证方法。您需要同时实现客户端和服务器端提供程序。有关详细信息,请参见 服务器开发人员指南 中的“身份验证 SPI”部分。

在此页面上