<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-client</artifactId>
<version>26.0.2</version>
</dependency>
</dependencies>
根据您的需求,资源服务器应该能够远程管理资源,甚至以编程方式检查权限。如果您使用 Java,可以使用授权客户端 API 访问 Keycloak 授权服务。
它针对的是希望访问服务器提供的不同端点的资源服务器,例如令牌端点、资源和权限管理端点。
<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
// 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);
// 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 进行客户端身份验证。
这是 OAuth2 规范中描述的传统方法。客户端有一个密钥,该密钥需要由客户端和 Keycloak 服务器同时知道。您可以在 Keycloak 管理控制台中为特定客户端生成密钥,然后将此密钥粘贴到应用程序端的 keycloak.json
文件中
"credentials": {
"secret": "19666a4f-32dd-4049-b082-684c74115f28"
}
这是基于 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 进行客户端身份验证相同,只是使用客户端密钥而不是私钥和证书。
客户端有一个密钥,该密钥需要由使用授权客户端的应用程序和 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”部分。