<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-client</artifactId>
<version>26.0.4</version>
</dependency>
</dependencies>
根据您的需求,资源服务器应该能够远程管理资源,甚至以编程方式检查权限。如果您正在使用 Java,您可以使用授权客户端 API 访问 Keycloak 授权服务。
它面向希望访问服务器提供的不同端点(例如令牌端点、资源和权限管理端点)的资源服务器。
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-client</artifactId>
<version>26.0.4</version>
</dependency>
</dependencies>
客户端配置在 keycloak.json
文件中定义,如下所示
{
"realm": "hello-world-authz",
"auth-server-url" : "https://127.0.0.1:8080",
"resource" : "hello-world-authz-service",
"credentials": {
"secret": "secret"
}
}
realm(必需)
Realm 的名称。
auth-server-url(必需)
Keycloak 服务器的基本 URL。所有其他 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 令牌,并使用其私钥对其进行签名,然后在特定请求中的 client_assertion
参数中将其发送到 Keycloak。
Keycloak 必须具有客户端的公钥或证书,以便它可以验证 JWT 上的签名。在 Keycloak 中,您为客户端配置客户端凭据。首先,在管理控制台的 凭据
选项卡中选择 签名 JWT
作为客户端身份验证方法。然后,您可以在 密钥
选项卡中选择以下方法之一
配置 JWKS URL,Keycloak 可以从该 URL 下载客户端的公钥。此选项是最灵活的,因为客户端可以随时轮换其密钥,并且 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"
}
}
“algorithm”字段指定使用客户端密钥的签名 JWT 的算法。它需要是以下值之一:HS256、HS384 和 HS512。有关详细信息,请参阅 JSON Web 算法 (JWA)。
“algorithm”字段是可选的;如果 keycloak.json
文件中不存在“algorithm”字段,则自动应用 HS256。
您也可以添加自己的客户端身份验证方法。您需要实现客户端和服务器端提供程序。有关更多详细信息,请参阅 服务器开发人员指南 中的 Authentication SPI
部分。