主题
authz-keycloak 
本文介绍了关于 APIX authz-keycloak 插件的基本信息及使用方法。
描述 
authz-keycloak 插件可用于通过 Keycloak Identity Server 添加身份验证。
TIP
虽然该插件是为了与 Keycloak 一起使用而开发的,但是它也可以与任何符合 OAuth/OIDC 或 UMA 协议的身份认证软件一起使用。
如果你想了解 Keycloak 的更多信息,请参考 Authorization Services Guide。
属性 
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 | 
|---|---|---|---|---|---|
| discovery | string | 否 | https://host.domain/auth/realms/foo/.well-known/uma2-configuration | Keycloak 授权服务的 discovery document 的 URL。 | |
| token_endpoint | string | 否 | https://host.domain/auth/realms/foo/protocol/openid-connect/token | 接受 OAuth2 兼容 token 的接口,需要支持 urn:ietf:params:oauth:grant-type:uma-ticket授权类型。 | |
| resource_registration_endpoint | string | 否 | https://host.domain/auth/realms/foo/authz/protection/resource_set | 符合 UMA 的资源注册端点。如果提供,则覆盖发现中的值。 | |
| client_id | string | 是 | 客户端正在寻求访问的资源服务器的标识符。 | ||
| client_secret | string | 否 | 客户端密码(如果需要)。 | ||
| grant_type | string | 否 | "urn:ietf:params:oauth:grant-type:uma-ticket" | ["urn:ietf:params:oauth:grant-type:uma-ticket"] | |
| policy_enforcement_mode | string | 否 | "ENFORCING" | ["ENFORCING", "PERMISSIVE"] | |
| permissions | array[string] | 否 | 描述客户端应用所需访问的资源和权限范围的字符串。格式必须为: RESOURCE_ID#SCOPE_ID。 | ||
| lazy_load_paths | boolean | 否 | false | [true, false] | 当设置为 true 时,使用资源注册端点而不是静态权限将请求 URI 动态解析为资源。 | 
| http_method_as_scope | boolean | 否 | false | [true, false] | 设置为 true 时,将 HTTP 请求类型映射到同名范围并添加到所有请求的权限。 | 
| timeout | integer | 否 | 3000 | [1000, ...] | 与 Identity Server 的 HTTP 连接超时(毫秒)。 | 
| access_token_expires_in | integer | 否 | 300 | [1, ...] | 访问令牌的有效期。 token. | 
| access_token_expires_leeway | integer | 否 | 0 | [0, ...] | access_token 更新的到期余地。设置后,令牌将在到期前几秒更新 access_token_expires_leeway。这避免了 access_token 在到达 OAuth 资源服务器时刚刚过期的情况。 | 
| refresh_token_expires_in | integer | 否 | 3600 | [1, ...] | 刷新令牌的失效时间。 | 
| refresh_token_expires_leeway | integer | 否 | 0 | [0, ...] | refresh_token 更新的到期余地。设置后,令牌将在到期前几秒刷新 refresh_token_expires_leeway。这样可以避免在到达 OAuth 资源服务器时 refresh_token 刚刚过期的错误。 | 
| ssl_verify | boolean | 否 | true | [true, false] | 设置为 true时,验证 TLS 证书是否与主机名匹配。 | 
| cache_ttl_seconds | integer | 否 | 86400 (equivalent to 24h) | positive integer >= 1 | 插件缓存插件用于向 Keycloak 进行身份验证的发现文档和令牌的最长时间(以秒为单位)。 | 
| keepalive | boolean | 否 | true | [true, false] | 当设置为 true时,启用 HTTP keep-alive 保证在使用后仍然保持连接打开。如果您期望对 Keycloak 有很多请求,请设置为true。 | 
| keepalive_timeout | integer | 否 | 60000 | positive integer >= 1000 | 已建立的 HTTP 连接将关闭之前的空闲时间。 | 
| keepalive_pool | integer | 否 | 5 | positive integer >= 1 | 连接池中的最大连接数。 | 
| access_denied_redirect_uri | string | 否 | [1, 2048] | 需要将用户重定向到的 URI,而不是返回类似 "error_description":"not_authorized"这样的错误消息。 | |
| password_grant_token_generation_incoming_uri | string | 否 | /api/token | 将此设置为使用密码授予类型生成令牌。该插件会将传入的请求 URI 与此值进行比较。 | 
注意:schema 中还定义了 encrypt_fields = {"client_secret"},这意味着该字段将会被加密存储在 etcd 中。具体参考 加密存储字段。
除上述释义外,还有以下需要注意的点:
- Discovery and endpoints - 使用 discovery属性后,authz-keycloak插件就可以从其 URL 中发现 Keycloak API 的端点。该 URL 指向 Keyloak 针对相应领域授权服务的发现文档。
- 如果发现文档可用,则插件将根据该文档确定令牌端点 URL。如果 URL 存在,则 token_endpoint和resource_registration_endpoint的值将被其覆盖。
 
- 使用 
- Client ID and secret - 该插件需配置 client_id属性来标识自身。
- 如果 lazy_load_paths属性被设置为true,那么该插件还需要从 Keycloak 中获得一个自身访问令牌。在这种情况下,如果客户端对 Keycloak 的访问是加密的,就需要配置client_secret属性。
 
- 该插件需配置 
- Policy enforcement mode - policy_enforcement_mode属性指定了在处理发送到服务器的授权请求时,该插件如何执行策略。- ENFORCINGmode:即使没有与给定资源关联的策略,请求也会默认被拒绝。- policy_enforcement_mode默认设置为- ENFORCING。
- PERMISSIVEmode:如果资源没有绑定任何访问策略,也被允许请求。
 
 
- Permissions - 在处理传入的请求时,插件可以根据请求的参数确定静态或动态检查 Keycloak 的权限。
- 如果 lazy_load_paths参数设置为false,则权限来自permissions属性。permissions中的每个条目都需要按照令牌端点预设的permission属性进行格式化。详细信息请参考 Obtaining Permissions.
 - :::note - 有效权限可以是单个资源,也可以是与一个或多个范围配对的资源。 - ::: - 如果 - lazy_load_paths属性设置为- true,则请求 URI 将解析为使用资源注册端点在 Keycloak 中配置的一个或多个资源。已经解析的资源被用作于检查的权限。- :::note - 需要该插件从令牌端点为自己获取单独的访问令牌。因此,请确保在 Keycloak 的客户端设置中设置了 - Service Accounts Enabled选项。- 还需要确保颁发的访问令牌包含具有 - uma_protection角色的- resource_access声明,以保证插件能够通过 Protection API 查询资源。- ::: 
- 自动将 HTTP method 映射到作用域 - http_method_as_scope通常与- lazy_load_paths一起使用,但也可以与静态权限列表一起使用。- 如果 - http_method_as_scope属性设置为- true,插件会将请求的 HTTP 方法映射到同名范围。然后将范围添加到每个要检查的权限。
- 如果 - lazy_load_paths属性设置为- false,则插件会将映射范围添加到- permissions属性中配置的任意一个静态权限——即使它们已经包含一个或多个范围。
 
- 使用 - password授权生成令牌- 如果要使用 - password授权生成令牌,你可以设置- password_grant_token_generation_incoming_uri属性的值。
- 如果传入的 URI 与配置的属性匹配并且请求方法是 POST,则使用 - token_endpoint生成一个令牌。
 - 同时,你还需要添加 - application/x-www-form-urlencoded作为- Content-Type标头,- username和- password作为参数。- 如下示例是当 - password_grant_token_generation_incoming_uri设置为- /api/token时的命令:shell- curl --location --request POST 'http://127.0.0.1:9080/api/token' \ --header 'Accept: application/json, text/plain, */*' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'username=<User_Name>' \ --data-urlencode 'password=<Password>'
如何启用 
以下示例为你展示了如何在指定 Route 中启用 authz-keycloak 插件,其中 ${realm} 是 Keycloak 中的 realm 名称:
shell
curl http://127.0.0.1:9180/apix/admin/routes/1 \
-H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
    "uri": "/get",
    "plugins": {
        "authz-keycloak": {
            "token_endpoint": "http://127.0.0.1:8090/auth/realms/${realm}/protocol/openid-connect/token",
            "permissions": ["resource name#scope name"],
            "client_id": "Client ID"
        }
    },
    "upstream": {
        "type": "roundrobin",
        "nodes": {
            "127.0.0.1:8080": 1
        }
    }
}'测试插件 
通过上述命令启用插件后,可以通过以下方法测试插件。
首先需要从 Keycloak 获取 JWT 令牌:
shell
curl \
  -d "client_id=<YOUR_CLIENT_ID>" \
  -d "username=<YOUR_USERNAMED>" \
  -d "password=<YOUR_PASSWORD>" \
  -d "grant_type=password" "http://<YOUR_KEYCLOAK_HOST>/auth/realms/${realm}/protocol/openid-connect/token"之后就可以使用获得的 JWT 令牌发起请求:
shell
curl http://127.0.0.1:9080/get \
-H 'Authorization: Bearer {JWT Token}'禁用插件 
当你需要禁用 authz-keycloak 插件时,可以通过以下命令删除相应的 JSON 配置,APISIX 将会自动重新加载相关配置,无需重启服务:
shell
curl http://127.0.0.1:9180/apix/admin/routes/1 \
-H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
    "uri": "/get",
    "plugins": {
    },
    "upstream": {
        "type": "roundrobin",
        "nodes": {
            "127.0.0.1:8080": 1
        }
    }
}'插件 Roadmap 
- 目前, - authz-keycloak插件通过要求定义资源名称和所需的范围,来强制执行路由策略。但 Keycloak 官方适配的其他语言客户端(Java、JavaScript)仍然可以通过动态查询 Keycloak 路径以及延迟加载身份资源的路径来提供路径匹配。在 APIX 之后发布的插件中即将支持此功能。
- 支持从 Keycloak JSON 文件中读取权限范畴和其他配置项。