策略执行点(PEP)是一种设计模式,因此你可以通过不同方式实现它。Keycloak 提供了在不同平台、环境和编程语言中实现 PEP 的所有必要方法。Keycloak 授权服务提供了一个 RESTful API,并利用 OAuth2 授权功能,通过集中式授权服务器实现细粒度授权。
Keycloak 提供的策略执行器有:
Java 策略执行器:适用于 Java 客户端应用程序。
JavaScript 策略执行器:适用于由 Keycloak JavaScript 适配器保护的应用程序。
Keycloak 服务器附带了一个 JavaScript 库,你可以使用它与由策略执行器保护的资源服务器进行交互。这个库基于 Keycloak JavaScript 适配器,可以进行集成,使你的客户端能够从 Keycloak 服务器获取权限。
你可以通过从 NPM 安装来获取这个库:
npm install keycloak-js
接下来,你可以按如下方式创建一个 KeycloakAuthorization 实例:
import Keycloak from "keycloak-js";
import KeycloakAuthorization from "keycloak-js/authz";
const keycloak = new Keycloak({
url: "
realm: "my-realm",
clientId: "my-app"
});
const authorization = new KeycloakAuthorization(keycloak);
await keycloak.init();
// Now you can use the authorization object to interact with the server.
keycloak-js/authz库提供了两个主要功能:
如果你正在访问 UMA 保护的资源服务器,使用权限票证从服务器获取权限。
通过发送应用程序想要访问的资源和范围,从服务器获取权限。
在这两种情况下,该库都能让你轻松地与资源服务器和 Keycloak 授权服务进行交互,以获取带有权限的令牌,你的客户端可以将其作为 Bearer 令牌,用于访问资源服务器上的受保护资源。
如果资源服务器由策略执行器保护,它会根据 Bearer 令牌携带的权限来响应客户端请求。通常,当你尝试使用缺少访问受保护资源权限的 Bearer 令牌访问资源服务器时,资源服务器会返回 401 状态码和WWW - Authenticate头
HTTP/1.1 401 Unauthorized
WWW-Authenticate: UMA realm="${realm-name}",
as_uri="https://${host}:${port}/realms/${realm-name}",
ticket="016f84e8-f9b9-11e0-bd6f-0021cc6004de"
有关更多信息,请参阅 UMA 授权流程。
你的客户端需要做的是从资源服务器返回的WWW - Authenticate头中提取权限票证,并使用该库按如下方式发送授权请求:
// prepare a authorization request with the permission ticket
const authorizationRequest = { ticket };
// send the authorization request, if successful retry the request
authorization.authorize(authorizationRequest).then((rpt) => {
// onGrant
}, () => {
// onDeny
}, () => {
// onError
});
authorize函数是完全异步的,并支持几个回调函数,用于接收来自服务器的通知:
onGrant:函数的第一个参数。如果授权成功,并且服务器返回带有请求权限的 RPT,回调将接收 RPT。
onDeny:函数的第二个参数。仅在服务器拒绝授权请求时调用。
onError:函数的第三个参数。仅在服务器响应异常时调用。
大多数应用程序应使用onGrant回调,在收到 401 响应后重试请求。后续请求应将 RPT 作为 Bearer 令牌包含在内以便重试
keycloak-js/authz库提供了一个entitlement函数,你可以使用它通过提供客户端想要访问的资源和范围,从服务器获取 RPT。
authorization.entitlement("my-resource-server-id").then((rpt) => {
// onGrant callback function.
// If authorization was successful you'll receive an RPT
// with the necessary permissions to access the resource server
});
authorization.entitlement("my-resource-server", {
permissions: [
{
id: "Some Resource"
}
]
}).then((rpt) => {
// onGrant
});
使用entitlement函数时,你必须提供想要访问的资源服务器的client_id。
entitlement函数是完全异步的,并支持几个回调函数,用于接收来自服务器的通知:
onGrant:函数的第一个参数。如果授权成功,并且服务器返回带有请求权限的 RPT,回调将接收 RPT。
onDeny:函数的第二个参数。仅在服务器拒绝授权请求时调用。
onError:函数的第三个参数。仅在服务器响应异常时调用。
authorize和entitlement函数都接受一个授权请求对象。这个对象可以设置以下属性:
一个对象数组,代表资源和范围。例如:
const authorizationRequest = {
permissions: [
{
id: "Some Resource",
scopes: ["view", "edit"]
}
]
}
metadata
一个对象,其属性定义服务器应如何处理授权请求。
response_include_resource_name:一个布尔值,指示服务器是否应在 RPT 的权限中包含资源名称。如果为false,则仅包含资源标识符。
response_permissions_limit:一个整数 N,定义 RPT 可拥有的权限数量限制。与rpt参数一起使用时,RPT 中只会保留最后 N 个请求的权限。
submit_request
一个布尔值,指示服务器是否应针对权限票证引用的资源和范围创建权限请求。此参数仅在作为 UMA 授权流程的一部分与ticket参数一起使用时才会生效。
如果你已经使用该库提供的任何授权函数获取了 RPT,你始终可以按如下方式从authorization对象中获取 RPT(假设它已通过前面所示的某种技术进行了初始化):
const rpt = authorization.rpt;