当前位置:   article > 正文

keycloak 认证服务_keycloak 只做认证

keycloak 只做认证

文章目录

1. 概述

https://www.keycloak.org/docs/latest/authorization_services/index.html

Keycloak支持细粒度的授权策略,并且能够组合不同的访问控制机制,例如:

  • Attribute-based access control (ABAC): 基于属性的安全控制
  • Role-based access control (RBAC): 基于角色的安全控制
  • User-based access control (UBAC): 基于用户的安全控制
  • Context-based access control (CBAC): 基于上下文的安全控制
  • Rule-based access control: 基于规则的安全控制
    • 使用Javascript
    • 使用 JBoss Drools
  • Time-based access control: 基于时间的安全控制
  • 通过策略提供程序服务提供程序接口(SPI)支持自定义访问控制机制(ACMs)

Keycloak基于一组管理UI和RESTful API,为受保护资源和作用域创建权限,将这些权限与授权策略相关联以及在应用程序和服务中强制执行授权决策的必要方法。

资源服务器(为受保护资源提供服务的应用程序或服务)通常依赖某种信息来决定是否应该向受保护资源授予访问权限。
对于基于RESTful的资源服务器,该信息通常从安全令牌获取,通常在每次请求发送到服务器时作为承载令牌发送。
对于依赖会话对用户进行身份验证的Web应用程序,该信息通常存储在用户的会话中,并从那里为每个请求检索。

通常,资源服务器仅基于基于角色的访问控制(RBAC)执行授权决策,其中,针对映射到这些相同资源的角色检查授予尝试访问受保护资源的用户的角色。
虽然角色非常有用并且被应用程序使用,但它们也有一些限制:

  • 资源和角色紧密耦合,角色更改(例如添加,删除或更改访问上下文)可能会影响多个资源
  • 对安全性要求的更改可能意味着对应用程序代码进行深度更改以反映这些更改
  • 根据您的应用程序大小,角色管理可能变得困难且容易出错
  • 不是最灵活的访问控制机制。角色不能代表你是谁,缺乏上下文信息。如果您已被授予角色,则您至少拥有一些访问权限。

考虑到今天我们需要考虑用户分布在不同地区,不同本地策略,使用不同设备以及对信息共享的高需求的异构环境,Keycloak授权服务可以帮助您提高应用程序和服务的授权功能通过提供:

  • 使用细粒度授权策略和不同访问控制机制的资源保护
  • 资源,权限的策略的集中管理
  • 集中的策略决策点
  • 基于REST的授权服务的REST安全性
  • 授权工作流程和用户管理的访问权限
  • 有助于避免跨项目(并重新部署)代码复制并快速适应安全要求变化的基础架构

1.1 架构

image
从设计角度来看,授权服务基于一组明确定义的授权模式,提供以下功能:

  • 策略管理点(Policy Administration Point/PAP)

    提供基于Keycloak管理控制台的一组UI,以管理资源服务器,资源,范围,权限和策略。部分内容也可以通过使用Protection API远程完成。

  • 策略决策点(PDP)

    提供可分发的策略决策点,指向发送授权请求的位置,并根据请求的权限相应地评估策略。有关更多信息,请参阅获取权限。

  • 策略执行点(PEP)

    提供不同环境的实现,以在资源服务器端实际执行授权决策。 Keycloak提供了一些内置的Policy Enforcer。

  • 策略信息点(PIP)

    基于Keycloak Authentication Server,可以从身份和运行时环境中获取属性。

1.1.1 认证流程

主要步骤为三个流程,以了解如何使用Keycloak为您的应用程序启用细粒度授权:

  • 资源管理
  • 权限和策略管理
  • 策略执行
资源管理
![image](https://img-blog.csdnimg.cn/img_convert/2d72f7181dc84da86950d18b35c310dc.png)

首先,您需要指定Keycloak您希望保护的内容,通常代表Web应用程序或一组一个或多个服务。有关资源服务器的更多信息,请参阅术语。

使用Keycloak管理控制台管理资源服务器。在那里,您可以启用任何已注册的客户端应用程序作为资源服务器,并开始管理您要保护的资源和范围。

image

资源可以是网页,RESTFul资源,文件系统中的文件,EJB等。它们可以表示一组资源(就像Java中的类一样),也可以表示单个特定资源。

例如,您可能拥有代表所有银行账户的银行账户资源,并使用它来定义所有银行账户共有的授权策略。但是,您可能希望为Alice帐户(属于客户的资源实例)定义特定策略,其中只允许所有者访问某些信息或执行操作。

可以使用Keycloak管理控制台或Protection API管理资源。在后一种情况下,资源服务器能够远程管理其资源。

范围通常表示可以对资源执行的操作,但它们不限于此。您还可以使用范围来表示资源中的一个或多个属性。

权限策略管理
定义资源服务器和要保护的所有资源后,必须设置权限和策略。

此过程涉及实际定义管理资源的安全性和访问要求的所有必要步骤。
image

策略定义了访问或执行某些操作(资源或范围)必须满足的条件,但它们与它们保护的内容无关。
它们是通用的,可以重用来构建权限甚至更复杂的策略。

例如,要仅允许授予角色“User Premium”的用户访问一组资源,您可以使用RBAC(基于角色的访问控制)。

Keycloak提供了一些内置策略类型(及其各自的策略提供者),涵盖了最常见的访问控制机制。您甚至可以根据使用JavaScript或JBoss Drools编写的规则创建策略。

定义策略后,即可开始定义权限。
权限与他们保护的资源相结合。
在此处指定要保护的内容(资源或范围)以及授予或拒绝权限必须满足的策略。

策略执行
策略实施涉及实际执行资源服务器的授权决策的必要步骤。这是通过在资源服务器上启用策略强制点或PEP来实现的,该策略强制点或PEP能够与授权服务器通信,请求授权数据并根据服务器返回的决策和权限控制对受保护资源的访问。

image

Keycloak提供了一些内置的Policy Enforcer实现,您可以使用它们来保护您的应用程序,具体取决于它们运行的平台。

1.1.2 认证服务

授权服务由以下RESTFul端点组成:

  • 令牌端点
  • 资源管理端点
  • 权限管理端点

这些服务中的每一个都提供了一个特定的API,涵盖了授权过程中涉及的不同步骤。

令牌端点
OAuth2客户端(例如前端应用程序)可以使用令牌端点从服务器获取访问令牌,并使用这些相同的令牌来访问受资源服务器保护的资源(例如后端服务)。

同样,Keycloak授权服务提供对OAuth2的扩展,以允许基于与所请求的资源或范围相关联的所有策略的处理来发布访问令牌。

这意味着资源服务器可以根据服务器授予的权限强制访问其受保护资源,并由访问令牌持有。
在Keycloak授权服务中,具有权限的访问令牌称为请求方令牌或简称RPT。

更多信息,请参阅获取权限。

Protection API
Protection API是一组符合UMA的端点,为资源服务器提供操作,以帮助他们管理与之关联的资源,范围,权限和策略。

只允许资源服务器访问此API,这也需要uma_protection范围。

Protection API提供的操作可以分为两大类:

  • 资源管理
    • 创建资源
    • 删除资源
    • 根据ID查找
    • 查询
  • 权限管理
    • 签发许可证

默认情况下,启用远程资源管理。您可以使用Keycloak管理控制台更改它,并且只允许通过控制台进行资源管理。

使用UMA协议时,Protection API发布权限票证是整个授权过程的重要部分。如后续部分所述,它们表示客户端请求的权限,并且发送到服务器以获取最终令牌,该最终令牌具有在评估与请求的资源和范围相关联的权限和策略期间授予的所有权限。

更多信息,请参阅Protection API。

1.2 术语

1.2.1 资源服务器(Resource Server)

资源服务器是托管受保护资源并能够接受和响应受保护资源请求的服务器

资源服务器通常依赖某种信息来决定是否应该授予对受保护资源的访问权限。
对于基于RESTful的资源服务器,该信息通常在安全令牌中携带,通常作为承载令牌以及每个请求发送到服务器。

依赖会话对用户进行身份验证的Web应用程序通常将该信息存储在用户的会话中,并从那里为每个请求检索它。

1.2.2 资源(Resource)

资源服务器通常依赖某种信息来决定是否应该授予对受保护资源的访问权限。
对于基于RESTful的资源服务器,该信息通常在安全令牌中携带,通常作为承载令牌以及每个请求发送到服务器。
依赖会话对用户进行身份验证的Web应用程序通常将该信息存储在用户的会话中,并从那里为每个请求检索它。

每个资源都有一个唯一标识符,可以表示单个资源或一组资源。
例如,您可以管理银行账户资源,该资源代表并定义所有银行账户的一组授权政策。
但您也可以使用名为Alice的银行账户的不同资源,该账户代表单个客户拥有的单一资源,该客户可以拥有自己的一组授权策略。

1.2.3 范围(Scope)

资源的范围是可以在资源上执行的有限访问范围。

在授权策略术语中,范围是可以逻辑地应用于资源的潜在许多动词之一。它通常表示可以使用给定资源执行的操作。

范围的示例包括查看,编辑,删除等。但是,范围也可以与资源提供的特定信息相关。在这种情况下,您可以拥有项目资源和成本范围,其中成本范围用于定义用户访问项目成本的特定策略和权限。

1.2.4 权限(Permission)

权限将受保护的对象与必须评估的策略相关联,以确定是否授予访问权限。

X CAN DO Y ON RESOURCE Z
  • 1
  • X: 表示一个或多个用户,角色或组,或它们的组合
  • Y: 表示要执行的操作,例如,写入,查看等
  • Z: 表示受保护资源,例如“/ accounts”。

Keycloak提供了一个丰富的平台,用于构建一系列权限策略,范围从简单到非常复杂,基于规则的动态权限。它提供了灵活性,有助于:

  • 减少代码重构和权限管理成本
  • 支持更灵活的安全模型,帮助您轻松适应安全要求的变化
  • 在运行时进行更改;应用程序只关心受保护的资源和范围,而不关心它们的保护方式。

1.2.5 策略(Policy)

策略定义了授予对象访问权限必须满足的条件。与权限不同,您不指定要保护的对象,而是指定访问给定对象必须满足的条件(例如,资源,范围或两者)。策略与可用于保护资源的不同访问控制机制(ACM)密切相关。使用策略,您可以实施基于属性的访问控制(ABAC),基于角色的访问控制(RBAC),基于上下文的访问控制或这些的任意组合的策略。

Keycloak利用策略的概念以及如何通过提供聚合策略的概念来定义它们,您可以在其中构建“policy of policies”并仍然控制评估的行为。Keycloak授权服务中的策略实现遵循分而治之的技术,而不是编写一个具有访问给定资源必须满足的所有条件的大型策略。也就是说,您可以创建单独的策略,然后使用不同的权限重用它们,并通过组合各个策略来构建更复杂的策略。

1.2.6 策略提供者(Policy Provider)

策略提供者是特定策略类型的实现。Keycloak提供内置策略,由相应的策略提供商提供支持,您可以创建自己的策略类型以支持您的特定需求。

Keycloak提供了一个SPI(服务提供程序接口),您可以使用它来插入自己的策略提供程序实现。

1.2.7 权限票据(Permission Ticket)

权限票证是由 用户管理访问(UMA) 规范定义的特殊类型的令牌,其提供不透明结构,其形式由授权服务器确定。此结构表示客户端请求的资源和/或范围,访问上下文,以及必须应用于授权数据请求的策略(请求方令牌[RPT])。

在UMA中,许可票证对于支持人与人之间的共享以及人与组织之间的共享至关重要。使用授权工作流的权限票证可以实现从简单到复杂的一系列方案,其中资源所有者和资源服务器可以根据管理对这些资源的访问的细粒度策略完全控制其资源。

更多信息, 查阅UMA章节用户管理控制(User-Managed-Access)

2 入门指南

首先需要安装keycloak

启动Keycloak Server

Linux/Unix

$ .../bin/standalone.sh -Djboss.socket.binding.port-offset=100
  • 1

Windows

> ...\bin\standalone.bat -Djboss.socket.binding.port-offset=100
  • 1

2.1 保护Servlet应用程序

入门指南的目的是让您尽快启动并运行,以便您可以试验并测试Keycloak提供的各种授权功能。
此快速浏览很大程度上依赖于默认的数据库和服务器配置,并不包括复杂的部署选项。
有关功能或配置选项的详细信息,请参阅本文档中的相应部分。

指南介绍了有关Keycloak授权服务的主要概念:

  • 为客户端应用程序启用细粒度授权
  • 将客户端应用程序配置为具有受保护资源的资源服务器
  • 定义权限和授权策略以管理对受保护资源的访问
  • 在应用中启用权限策略

2.2 创建 Realm 和 用户

主要为以下步骤:

  1. 创建一个名为hello-world-authz的领域。创建后,将显示类似于以下内容的页面: Realm hello-world-authz
    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
  2. 在新创建的领域中创建用户。
    单击 Users。
  3. 在用户列表的右侧,单击Add user。
  4. 创建新用户,请填写“用户名”,“电子邮件”,“名字”和“姓氏”字段。单击“User Enabled”开关,单击“On”,然后单击“Save”。
    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
  5. 单击“凭据”选项卡为用户设置密码。
    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
  6. 使用密码填写“新密码”和“密码确认”字段,关闭“Temporary”选项。
  7. 单击“重置密码”以设置用户密码

2.3 启用授权服务

您可以在配置为使用OpenID Connect协议的现有客户端应用程序中启用授权服务。您还可以创建新客户端。

创建客户端

  1. 单击“Clients”以开始创建新的客户端应用程序,并填写“Client ID”,“Client Protocol”和“Root URL”字段。
    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
  2. 单击保存, 客户端详情页面
    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
  3. 开启授权: Authorization Enabled 并保存,会展示一个新的 Authorization 选项卡
  4. 单击“授权”选项卡,将显示类似于以下内容的“授权设置”页面
    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

为客户端应用程序启用授权服务时,Keycloak会自动为客户端授权配置创建多个默认设置。

更多信息,查看 启用授权服务 章节

2.4 构建,部署,测试你的应用

前一章节已正确配置app-authz-vanilla资源服务器(或客户端)并启用了授权服务,则可以将其部署到服务器。

Keycloak Quickstarts Repository中提供了您要部署的应用程序的项目和代码。
您需要在计算机上安装以下内容并在PATH中使用,然后才能继续:

  • Java JDK 8
  • Apache Maven 3.1.1+
  • Git

克隆项目

$ git clone https://github.com/keycloak/keycloak-quickstarts
  • 1

本节构建和部署的项目位于:

$ cd keycloak-quickstarts/app-authz-jee-vanilla
  • 1

2.4.1 获取适配器配置

在构建和部署应用程序之前,必须首先获取适配器配置。

要从Keycloak管理控制台获取适配器配置,请完成以下步骤:

  1. 单击“客户端”。在客户端列表中,单击app-authz-vanilla客户端应用程序。
    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
  2. 单击“Installation”选项卡。从Format Option下拉列表中,选择Keycloak OIDC JSON。适配器配置以JSON格式显示。单击Download。
    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
  3. 复制文件 keycloak.json 到 app-authz-jee-vanilla/config 目录
  4. (可选)默认情况下,当用户缺少访问资源服务器上受保护资源的权限时,策略实施器将使用403状态代码进行响应。但是,您也可以为未授权用户指定重定向URL。要指定重定向URL,请编辑在步骤3中更新的keycloak.json文件,并使用以下内容替换策略实施器配置:默认情况下,当用户缺少访问资源服务器上受保护资源的权限时,策略实施器将使用403状态代码进行响应。但是,您也可以为未授权用户指定重定向URL。要指定重定向URL,请编辑在步骤3中更新的keycloak.json文件,并使用以下内容替换策略实施器配置:
"policy-enforcer": {
    "on-deny-redirect-to" : "/app-authz-vanilla/error.jsp"
}
  • 1
  • 2
  • 3

如果用户没有访问受保护资源的必要权限,而不是无用的403 Unauthorized消息,则此更改指定策略实施者将用户重定向到/app-authz-vanilla/error.jsp页面。

2.4.2 构建部署应用

$ cd redhat-sso-quickstarts/app-authz-jee-vanilla
$ mvn clean package wildfly:deploy
  • 1
  • 2

2.4.3 测试应用

应用部署成功, 访问: http://localhost:8080/app-authz-vanilla

登录页面:
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

使用之前创建的 alice 用户登录

主页面:
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

为客户端应用程序启用授权服务时,Keycloak定义的默认设置提供了一个简单的策略,该策略将为资源提供授权访问权限

您可以从更改默认权限和策略开始,测试应用程序的响应方式,甚至使用Keycloak提供的不同策略类型创建新策略

你现在可以做很多事情来测试这个应用程序。
例如,您可以通过单击客户端的“Authorization”选项卡,然后单击“Policies”选项卡,然后单击列表中的“Default Policy”来更改默认策略,以允许您更改它,如下所示:

// The default value is $evaluation.grant(),
// let's see what happens when we change it to $evaluation.deny()
$evaluation.deny();
  • 1
  • 2
  • 3

现在注销掉重新登录, 将无法访问应用
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

恢复默认的策略这个问题,不更改默认策略代码,而是使用策略代码文本区域下方的下拉列表将Logic更改为Negative。

这会重新启用对应用程序的访问,因为我们正在否定该策略的结果,该策略默认拒绝所有访问请求。
同样,在测试此更改之前,请务必注销并再次登录。

2.4.4 下一步

您还可以执行其他操作,例如:

  • 创建范围,为其定义策略和权限,并在应用程序端对其进行测试。用户可以执行操作(或您创建的范围表示的任何其他内容)吗?
  • 创建不同类型的策略(如基于规则),并将这些策略与默认权限相关联。
  • 将多个策略应用于“默认权限”并测试该行为。例如,组合多个策略并相应地更改决策策略。
  • 有关如何查看和测试应用程序内部权限的详细信息,请参阅获取授权上下文

2.5 授权 Quickstarts

除了在上一节中用作示例应用程序的app-authz-jee-vanilla快速入门之外,Keycloak Quickstarts Repository还包含其他使用本文档中描述的授权服务的应用程序。

每个quickstarts都有一个README文件,其中包含有关如何构建,部署和测试示例应用程序的说明。下表提供了可用授权快速入门的简要说明:

NameDescription
app-authz-jee-servlet演示如何为Java EE应用程序启用细粒度授权,以便根据从Keycloak Server获取的权限保护特定资源并构建动态菜单。
app-authz-jee-vanilla演示如何为Java EE应用程序启用细粒度授权,并使用默认授权设置来保护应用程序中的所有资源。
app-authz-rest-springboot演示如何使用Keycloak授权服务保护SpringBoot REST服务。
app-authz-springboot演示如何编写SpringBoot Web应用程序,其中身份验证和授权方面由Keycloak管理。
app-authz-uma-photoz一个基于HTML5 + AngularJS + JAX-RS的简单应用程序,演示如何启用对应用程序的用户管理访问,并允许用户管理其资源的权限。

3. 管理资源服务器

根据OAuth2规范,资源服务器是托管受保护资源并能够接受和响应受保护资源请求的服务器。

在Keycloak中,资源服务器具有丰富的平台,用于对其受保护资源进行细粒度授权,其中可以基于不同的访问控制机制做出授权决策。

可以将任何客户端应用程序配置为支持细粒度权限。
这样做,您在概念上将客户端应用程序转换为资源服务器。

3.1 创建 Client Application

启用Keycloak授权服务的第一步是创建要转换为资源服务器的客户端应用程序。

  1. Click Clients.
  2. Click Create
    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
  3. 输入 Client ID, 例如: my-resource-server
  4. 输入 Root URL
http://${host}:${port}/my-resource-server
  • 1
  1. Click Save
    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3.2 启用授权服务

要将OIDC客户端应用程序转换为资源服务器并启用细粒度授权,请启用 Authorization Enabled 选项。

将为此客户端显示新的“Authorization”选项卡。单击“Authorization”选项卡,将显示类似于以下内容的页面:
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

“Authorization”选项卡包含其他子选项卡,其中包含实际保护应用程序资源必须遵循的不同步骤。
每个选项卡都由本文档中的特定主题单独介绍。
但这里有一个关于每一个的快速描述:

  • Settings

    资源服务器的常规设置。有关此页面的更多详细信息,请参阅资源服务器设置部分。
  • Resource

    在此页面中,您可以管理应用程序的资源。
  • Authorization Scopes
    在此页面中,您可以管理范围。
  • Policies
    在此页面中,您可以管理授权策略并定义授予权限时必须满足的条件。
  • Permissions
    在此页面中,您可以通过将受保护资源和范围与您创建的策略相链接来管理受保护资源和范围的权限。
  • Evaluate

    在此页面中,您可以模拟授权请求并查看已定义的权限和授权策略的评估结果。
  • Export: 导出配置

3.2.1 资源服务器设置

在“资源服务器设置”页面上,您可以配置策略强制模式,允许远程资源管理以及导出授权配置设置。

  • Policy Enforcement Mode

    指定在处理发送到服务器的授权请求时如何强制实施策略
    • Enforcing

      (默认),默认情况下,即使没有与给定资源关联的策略,也会拒绝请求
    • Permissive

      即使没有与给定资源关联的策略,也允许请求。
    • Disabled

      禁用所有策略的评估,并允许访问所有资源。

3.3 默认配置

创建资源服务器时,Keycloak会为新创建的资源服务器创建默认配置.

默认配置包括:

  • 一个默认受保护的资源匹配系统中所有的资源
  • 始终授予对此策略保护的资源的访问权限的策略。
  • 根据默认策略管理对所有资源的访问的权限。

默认受保护资源称为默认资源,如果导航到“Resource”选项卡,则可以查看它。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

此资源定义了一个Type,即urn:my-resource-server:resources:default和URI / *。这里,URI字段定义了一个通配符模式,该模式向Keycloak指示此资源表示应用程序中的所有路径。换句话说,在为应用程序启用策略实施时,将在授予访问权限之前检查与资源关联的所有权限。

前面提到的类型定义了一个值,该值可用于创建必须应用于默认资源或使用相同类型创建的任何其他资源的类型化资源权限。

默认策略被称为唯一来自领域策略,如果导航到“Policy”选项卡,则可以查看它。
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

此策略是基于JavaScript的策略,用于定义始终授予对此策略保护的资源的访问权限的条件。如果单击此策略,您可以看到它定义了一条规则,如下所示:

// by default, grants any permission associated with this policy
$evaluation.grant();
  • 1
  • 2

最后,默认权限称为默认权限,如果导航到“Permission”选项卡,则可以查看它。
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

此权限是基于资源的权限,用于定义一组应用于具有给定类型的所有资源的一个或多个策略。

3.3.1 更改默认配置

您可以通过删除默认资源,策略或权限定义并创建自己的配置来更改默认配置。

使用URI创建默认资源,该URI使用/ *模式映射到应用程序中的任何资源或路径。
在创建自己的资源,权限和策略之前,请确保默认配置不会与您自己的设置冲突。

默认配置定义映射到应用程序中所有路径的资源。如果您要为自己的资源写入权限,请确保删除默认资源或将其URIS字段更改为应用程序中更具体的路径。否则,与默认资源关联的策略(默认情况下始终授予访问权限)将允许Keycloak授予对任何受保护资源的访问权限。

3.4 导出和导入授权配置

可以导出和下载资源服务器(或客户端)的配置设置。
您还可以导入资源服务器的现有配置文件。
当您要为资源服务器创建初始配置或更新现有配置时,导入和导出配置文件很有用。
配置文件包含以下定义:

  • 受保护的资源合范围
  • 策略(Policies)
  • 权限(Permissions)

3.4.1 导出配置文件

  1. 导航到 Resource Server Settings 页面
  2. 点击 Export Settings 选项卡
  3. 点击 Export 导出
    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

配置文件以JSON格式导出并显示在文本区域中,您可以从中复制和粘贴。
您也可以单击“下载”下载配置文件并保存。

4. 管理资源和范围

资源管理比较简单
创建资源服务器后,您可以开始创建要保护的资源和范围。
可以通过分别导航到Resource和Scope选项卡来管理资源和范围。

4.1 查看资源

在“资源”页面上,您可以看到与资源服务器关联的资源列表。
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

资源列表提供有关受保护资源的信息:

  • Type: 类型
  • URIS: URIS
  • Owner: 资源拥有者
  • Associated scopes, if any: 相关范围, 如果有
  • Associated permissions: 相关权限

在此列表中,您还可以通过单击要为其创建权限的资源的“Create Permission”来直接创建权限。

在为资源创建权限之前,请确保已经定义了要与权限关联的策略。

4.2 创建资源

创建资源非常简单和通用。
您主要关心的是您创建的资源的粒度。
换句话说,可以创建资源来表示一组一个或多个资源,并且定义它们的方式对于管理权限至关重要。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
在Keycloak中,资源定义了一组对不同类型资源通用的信息,例如:

  • Name

    资源名称
  • Type

    唯一标识一个或多个资源集的类型的字符串。

    该类型是用于对不同资源实例进行分组的字符串。
    例如,自动创建的默认资源的默认类型是urn:resource-server-name:resources:default
  • Scopes

    与资源关联的一个或多个范围。

4.2.1 资源属性

资源可能具有与之关联的属性。这些属性可用于提供有关资源的其他信息,并在评估与资源关联的权限时为策略提供其他信息。

每个属性都是键和值对,其中值可以是一个或多个字符串的集合。
通过用逗号分隔每个值,可以为属性定义多个值。

4.2.2 Typed Resources

资源的类型字段可用于将不同的资源组合在一起,因此可以使用一组通用权限来保护它们。

4.2.3 资源所有者

资源也有所有者。默认情况下,资源由资源服务器拥有。

但是,资源也可以与用户关联,因此您可以基于资源所有者创建权限。
例如,仅允许资源所有者删除或更新给定资源。

4.2.4 远程管理资源

资源管理也通过Protection API公开,以允许资源服务器远程管理其资源。

使用Protection API时,可以实施资源服务器来管理其用户拥有的资源。在这种情况下,您可以指定用户标识符以将资源配置为属于特定用户。

Keycloak为资源服务器提供对其资源的完全控制。
将来,我们应该能够允许用户控制自己的资源以及批准授权请求和管理权限,尤其是在使用UMA协议时。

5. 管理策略

如上所述,策略定义在授予对象访问权限之前必须满足的条件。

通过在编辑资源服务器时单击“Policy”选项卡,可以查看与资源服务器关联的所有策略。
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在此选项卡上,您可以查看以前创建的策略列表以及创建和编辑策略。
要创建新策略,请在策略列表的右上角,从“创建策略”下拉列表中选择策略类型。有关每种策略类型的详细信息,请参阅本节。

5.1 基于用户的访问策略(User-Based Policy)

可以使用此类策略来定义允许一组一个或多个用户访问对象权限。

要创建新的基于用户的策略,请在策略列表右上角的下拉列表中选择User。

Add a User-Based Policy
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5.1.1 配置

  • Name

    策略名称。最佳做法是使用与您的业务和安全要求密切相关的名称,以便您可以更轻松地识别它们。
  • Description

    此策略的描述信息
  • Users

    指定此策略授予哪些用户访问权限。
  • Logic

    在评估其他条件后应用此政策的逻辑。

5.2 基于角色的访问策略(Role-Based Policy)

您可以使用此类策略为允许一组一个或多个角色访问对象的权限定义条件。

默认情况下,没有指定添加到此策略的角色,如果该用户的任何一个角色被授予该权限,则策略将授予访问权限。

如果要强制执行特定角色,则可以根据需要指定特定角色。您还可以组合必需和非必需的角色,无论它们是领域角色还是客户角色。

当您需要更多受限制的基于角色的访问控制(RBAC)时,角色策略非常有用,其中必须强制执行特定角色以授予对对象的访问权限。
例如,您可以强制用户必须同意允许客户端应用程序(代表用户)访问用户的资源。
您可以使用Keycloak客户端作用域映射来启用同意页面,甚至强制客户端在从Keycloak服务器获取访问令牌时显式提供作用域。

要创建新的基于角色的策略,请在策略列表右上角的下拉列表中选择“Role”。

Add Role-Based Policy
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5.2.1 配置

  • Name

    策略名称
  • Description

    描述信息
  • Realm Roles

    指定此策略允许的领域角色。
  • Client Roles

    指定此策略允许的客户端角色。要启用此字段,必须先选择一个客户端。
  • Logic
    在评估其他条件后应用策略的逻辑。

5.2.2 定义必须的角色

创建基于角色的策略时,可以将特定角色指定为必需。执行此操作时,仅当请求访问权限的用户已被授予所有必需角色时,策略才会授予访问权限。可以像这样配置域和客户端角色。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

定义必须的角色,需要勾选"Required"复选框

当您的策略定义多个角色但只有其中一部分是必需的时,必须的角色非常有用。
在这种情况下,您可以组合领域和客户端角色,以便为您的应用程序启用更细粒度的基于角色的访问控制(RBAC)模型。
例如,您可以拥有特定于客户端的策略,并且需要与该客户端关联的特定客户端角色。
或者,您可以强制仅在存在特定领域角色的情况下授予访问权限。
您还可以在同一策略中组合这两种方法。

5.3 JavaScript-Based Policy

您可以使用此类策略来使用JavaScript定义权限的条件。
它是Keycloak支持的基于规则的策略类型之一,并提供基于Evaluation API编写任何策略的灵活性。

要创建基于JavaScript的策略,请在策略列表右上角的下拉列表中选择JavaScript。

Add Javascript Policy
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5.3.1 配置

  • Name

    策略名称
  • Description

    描述信息
  • Code

    提供此策略条件的JavaScript代码。
  • Logic
    在评估其他条件后应用策略的逻辑。

5.3.2 示例

从Evaluation上下文检查属性
以下是基于JavaScript的策略的简单示例,该策略使用基于属性的访问控制(ABAC)来定义基于从执行上下文获取的属性的条件:
var context = $evaluation.getContext();
var contextAttributes = context.getAttributes();

if (contextAttributes.containsValue('kc.client.network.ip_address', '127.0.0.1')) {
    $evaluation.grant();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
从当前 Identity 检查属性

以下是基于JavaScript的策略的简单示例,该策略使用基于属性的访问控制(ABAC)来定义基于与当前标识关联的属性的条件:

var context = $evaluation.getContext();
var identity = context.getIdentity();
var attributes = identity.getAttributes();
var email = attributes.getValue('email').asString(0);

if (email.endsWith('@keycloak.org')) {
    $evaluation.grant();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这些属性是根据授权请求中使用的令牌中定义的任何声明进行映射的

检查当前身份所授予的角色
您还可以在策略中使用基于角色的访问控制(RBAC)。在下面的示例中,我们检查用户是否被授予keycloak_user领域角色:
var context = $evaluation.getContext();
var identity = context.getIdentity();

if (identity.hasRealmRole('keycloak_user')) {
    $evaluation.grant();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

或者,您可以检查用户是否被授予my-client-role客户端角色,其中my-client是客户端应用程序的客户端ID:

var context = $evaluation.getContext();
var identity = context.getIdentity();

if (identity.hasClientRole('my-client', 'my-client-role')) {
    $evaluation.grant();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
检查用户授予的角色
要检查授予用户的领域角色:
var realm = $evaluation.getRealm();

if (realm.isUserInRealmRole('marta', 'role-a')) {
    $evaluation.grant();
}
  • 1
  • 2
  • 3
  • 4
  • 5

或者检查客户端角色是否授予用户

var realm = $evaluation.getRealm();

if (realm.isUserInClientRole('marta', 'my-client', 'some-client-role')) {
    $evaluation.grant();
}
  • 1
  • 2
  • 3
  • 4
  • 5

检查领域角色是否授权给组

var realm = $evaluation.getRealm();

if (realm.isGroupInRole('/Group A/Group D', 'role-a')) {
    $evaluation.grant();
}
  • 1
  • 2
  • 3
  • 4
  • 5

将任意声明推送到资源服务器 要将任意声明推送到资源服务器,以便提供有关如何强制执行权限的其他信息:

var permission = $evaluation.getPermission();

// decide if permission should be granted

if (granted) {
    permission.addClaim('claim-a', 'claim-a');
    permission.addClaim('claim-a', 'claim-a1');
    permission.addClaim('claim-b', 'claim-b');
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

检查组成员身份

var realm = $evaluation.getRealm();

if (realm.isUserInGroup('marta', '/Group A/Group B')) {
    $evaluation.grant();
}
  • 1
  • 2
  • 3
  • 4
  • 5
混合不同的访问控制机制
您还可以使用多种访问控制机制的组合。 以下示例显示了如何在同一策略中使用角色(RBAC)和声明/属性(ABAC)检查。 在这种情况下,我们检查用户是否被授予管理员角色或是否有来自keycloak.org域的电子邮件:
var context = $evaluation.getContext();
var identity = context.getIdentity();
var attributes = identity.getAttributes();
var email = attributes.getValue('email').asString(0);

if (identity.hasRealmRole('admin') || email.endsWith('@keycloak.org')) {
    $evaluation.grant();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

编写自己的规则时,请记住$ evaluation对象是实现org.keycloak.authorization.policy.evaluation.Evaluation的对象。有关可从此界面访问的内容的更多信息,请参阅Evaluation API。

5.4 基于规则的访问策略

使用此类策略,您可以使用Drools(规则评估环境)定义权限的条件。它是Keycloak支持的基于规则的策略类型之一,并提供基于Evaluation API编写任何策略的灵活性。

要创建新的基于规则的策略,请在策略列表右上角的下拉列表中选择“Rule”

Add Rule Policy
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5.4.1 配置

  • Name

    规则名称
  • Description

    规则描述
  • Policy Maven Artifact

    Maven groupId-artifactId-version(GAV)指向定义规则的工件。提供GAV后,可以单击“Resolve”以加载“Module”和“Session”字段。
    • Group Id

      The groupId of the artifact.
    • Artifact Id

      The artifactId of the artifact.
    • Version
      The version of the artifact.
  • Module

    策略使用的模块。您必须提供一个模块来选择将从中加载规则的特定会话。
  • Session

    策略使用的会话。会话提供了处理策略时要评估的所有规则。
  • Update Period

    指定扫描更新的间隔。
  • Logic

    在Evaluation其他条件后应用此政策的逻辑。

5.4.2 示例

以下是基于Drools的策略的简单示例,该策略使用基于属性的访问控制(ABAC)来定义仅在经过身份验证的用户是所请求资源的所有者时才评估为GRANT的条件:

import org.keycloak.authorization.policy.evaluation.Evaluation;
rule "Authorize Resource Owner"
    dialect "mvel"
    when
       $evaluation : Evaluation(
           $identity: context.identity,
           $permission: permission,
           $permission.resource != null && $permission.resource.owner.equals($identity.id)
       )
    then
        $evaluation.grant();
end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

您可以使用另一个ABAC变体来从标识中获取属性并相应地定义条件:

import org.keycloak.authorization.policy.evaluation.Evaluation;
rule "Authorize Using Identity Information"
    dialect "mvel"
    when
       $evaluation : Evaluation(
           $identity: context.identity,
           identity.attributes.containsValue("someAttribute", "you_can_access")
       )
    then
        $evaluation.grant();
end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

有关可以从org.keycloak.authorization.policy.evaluation.Evaluation界面访问的内容的更多信息,请参阅Evaluation API。

5.5 基于时间的访问策略

您可以使用此类策略来定义权限的时间条件。

要创建新的基于时间的策略,请在策略列表右上角的下拉列表中选择"Time"。

Add Time Policy
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5.5.1 配置

  • Name

    规则名称
  • Description

    规则描述
  • Not Before

    定义不得授予访问权限的时间。
    仅当当前日期/时间晚于或等于此值时才授予权限
  • Not On or After

    定义不得授予访问权限的时间。仅当当前日期/时间早于或等于此值时才授予权限。
  • Day of Month

    定义必须授予访问权限的日期。您还可以指定一系列日期。在这种情况下,仅当月中的当前日期介于或等于指定的两个值时才授予权限
  • Month

    定义必须授予访问权限的月份。您还可以指定一个月的范围。在这种情况下,仅当当前月份介于或等于指定的两个值时才授予权限。
  • Year

    定义必须授予访问权限的年份。您还可以指定年份范围。在这种情况下,仅当当前年份介于或等于指定的两个值时才授予权限。
  • Hour

    定义必须授予访问权限的小时。您还可以指定一个小时范围。在这种情况下,仅当当前小时介于或等于指定的两个值时才授予权限。
  • Minute

    定义必须授予访问权限的分钟。您还可以指定分钟范围。在这种情况下,仅当当前分钟介于或等于指定的两个值时才授予权限。
  • Logic

    在Evaluation其他条件后应用此政策的逻辑。

只有满足所有条件,才能授予访问权限。 Keycloak将根据每个条件的结果执行AND。

5.6 聚合策略

如前所述,Keycloak允许您构建策略策略,这一概念称为聚合策略。您可以使用策略聚合来重用现有策略来构建更复杂的策略,并使您的权限与处理授权请求期间评估的策略更加分离。

要创建新的聚合策略,请在策略列表右上角的下拉列表中选择“Aggregated”。

Add an Aggregated Policy
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

假设您有一个名为机密资源的资源,只能由来自keycloak.org域的用户和特定范围的IP地址访问。您可以使用这两个条件创建单个策略。但是,您希望重用此策略的域部分以应用于无论源网络如何都运行的权限。您可以为域和网络条件创建单独的策略,并根据这两个策略的组合创建第三个策略。使用聚合策略,您可以自由组合其他策略,然后将新聚合策略应用于您想要的任何权限。

创建聚合策略时,请注意不要在策略之间引入循环引用或依赖关系。如果检测到循环依赖关系,则无法创建或更新策略。

5.6.1 配置

  • Name

    规则名称
  • Description

    规则描述
  • Apply Policy

    定义一组与聚合策略关联的一个或多个策略。要关联策略,您可以选择现有策略,也可以通过选择要创建的策略类型来创建新策略。
  • Decision Strategy

    此权限的决策策略。
  • Logic

    在Evaluation其他条件后应用此政策的逻辑。

5.6.2 决策策略(Decision Strategy)

在创建聚合策略时,您还可以定义决策策略,该策略将用于根据每个策略的结果确定最终决策。

  • Unanimous

    默认策略(如果未提供)。一致的,所有的策略都必须决策通过,最终决策通过.
  • Affirmative

    肯定的, 只要有一项策略决策通过, 最终则决策通过
  • Consensus

    共识, 当决策通过的数量大于或等于决策不同过的策略, 则最终决策通过, 反之不通过

5.7 基于客户端的访问策略

您可以使用此类策略来定义允许一组一个或多个客户端访问对象的权限条件。

要创建新的基于客户端的策略,请在策略列表右上角的下拉列表中选择“Client”

Add a Client-Based Policyimage

5.7.1 配置

  • Name

    规则名称
  • Description

    规则描述
  • Clients

    指定要搜于哪些客户端的访问权限
  • Logic

    在Evaluation其他条件后应用此政策的逻辑。

5.8 基于组的访问策略

Add Group-Based Policy
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5.8.1 配置

  • Name

    规则名称
  • Description

    规则描述
  • Groups Claim

    组声明, 指定包含组名称和/或路径的令牌中的声明的名称。
    通常,授权请求获取某个用户的客户端的ID令牌或访问令牌。
    如果已定义,则令牌必须包含此策略将从哪里获取用户所属的组的声明。
    如果未定义,则从您的领域配置中获取用户组。
  • Groups

    允许您在评估权限时选择应由此策略强制执行的组。添加组后,您可以通过标记“Extend to Children 扩展到子项”复选框来扩展对组的子项的访问权限。
    如果未标记,则访问限制仅适用于所选组。
  • Logic

    在Evaluation其他条件后应用此政策的逻辑。

5.8.2 扩展访问权限到子分组

默认情况下,向此策略添加组时,访问限制仅适用于所选组的成员。

在某些情况下,可能有必要不仅允许访问组本身,还允许访问层次结构中的任何子组。对于添加的任何组,您可以标记一个复选框Extend to Children以扩展对子组的访问。

Extending Access to Child Groups
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在上面的示例中,该策略授予IT或其任何子级的任何用户成员的访问权限

5.9 正面和负面推理(Logic)

可以使用正逻辑或负逻辑配置策略。
简而言之,您可以使用此选项来定义策略结果是保持原样还是被否定。

例如,假设您要创建一个策略,其中只应授予未授予特定角色的用户访问权限。
在这种情况下,您可以使用该角色创建基于角色的策略,并将其逻辑字段设置为Negative。
如果保持 Positive,这是默认行为,则策略结果将保持不变。

  • Positive: 保持策略结果
  • Negative: 对策略结果进行取反

5.10 Policy Evaluation API

使用JavaScript或JBoss Drools编写基于规则的策略时,Keycloak提供了一个评估API,它提供了有用的信息来帮助确定是否应该授予权限。

此API由几个接口组成,可让您访问信息,例如:

  • 正在评估的权限,表示所请求的资源和范围。
  • 与请求的资源关联的属性
  • 运行时环境以及与执行上下文关联的任何其他属性
  • 有关用户的信息,例如组成员身份和角色

主界面是org.keycloak.authorization.policy.evaluation.Evaluation,它定义了以下合同:

public interface Evaluation {

    /**
     * Returns the {@link ResourcePermission} to be evaluated.
     *
     * @return the permission to be evaluated
     */
    ResourcePermission getPermission();

    /**
     * Returns the {@link EvaluationContext}. Which provides access to the whole evaluation runtime context.
     *
     * @return the evaluation context
     */
    EvaluationContext getContext();

    /**
     * Returns a {@link Realm} that can be used by policies to query information.
     *
     * @return a {@link Realm} instance
     */
    Realm getRealm();

    /**
     * Grants the requested permission to the caller.
     */
    void grant();

    /**
     * Denies the requested permission.
     */
    void deny();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

处理授权请求时,Keycloak会在评估任何策略之前创建一个Evaluation实例。
然后将此实例传递给每个策略以确定访问是GRANT还是DENY。

策略通过在Evaluation实例上调用grant()或deny()方法来确定此方法。

默认情况下,Evaluation实例的状态为拒绝,这意味着您的策略必须显式调用grant()方法,以向策略评估引擎指示应该授予权限。
有关Evaluation

API的更多信息,请参阅JavaDocs。

5.10.1 The Evaluation Context

public interface EvaluationContext {

    /**
     * Returns the {@link Identity} that represents an entity (person or non-person) to which the permissions must be granted, or not.
     *
     * @return the identity to which the permissions must be granted, or not
     */
    Identity getIdentity();

    /**
     * Returns all attributes within the current execution and runtime environment.
     *
     * @return the attributes within the current execution and runtime environment
     */
    Attributes getAttributes();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

通过该接口,策略可以获取:

  • 认证过的身份 - Identity
  • 上下文环境信息

Identity是基于与授权请求一起发送的OAuth2访问令牌构建的,并且此构造可以访问从原始令牌中提取的所有声明。例如,如果您使用Protocol Mapper 在OAuth2访问令牌中包含自定义声明,您还可以从策略访问此声明并使用它来构建条件。

EvaluationContext还允许您访问与执行和运行时环境相关的属性。目前,只有少数内置属性。

NameDescriptionType
kc.time.date_time当前日期时间String. Format MM/dd/yyyy hh:mm:ss
kc.client.network.ip_addressIPv4 address of the clientString
kc.client.network.host客户端主机名称String
kc.client.idThe client idString
kc.client.user_agentThe value of the ‘User-Agent’ HTTP headerString[]
kc.realm.nameThe name of the realmString

6. 管理权限

权限将受保护的对象与必须评估的策略相关联,以决定是否应授予访问权限。

在创建要保护的资源以及要用于保护这些资源的策略之后,您可以开始管理权限。
要管理权限,请在编辑资源服务器时单击“Permissions”选项卡。

Permissions
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

可以创建权限以保护两种主要类型的对象:

  • Resources: 资源
  • Scopes: 范围

要创建权限,请从权限列表右上角的下拉列表中选择要创建的权限类型。以下部分更详细地描述了这两种类型的对象。

6.1 创建基于资源的权限

要创建新的基于资源的权限,请在权限列表右上角的下拉列表中选择“Resource-based”。

Add Resource-Based Permission
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

6.1.1 配置

  • Name

    名称
  • Description

    描述
  • Apply To Resource Type

    指定是否将权限应用于具有给定类型的所有资源。选择此字段时,系统会提示您输入要保护的资源类型。
    • Resource Type

      定义要保护的资源类型。定义时,将评估与该类型匹配的所有资源的此权限。
  • Resources

    定义一组要保护的一个或多个资源。
  • Apply Policy

    定义一组与权限关联的一个或多个策略。要关联策略,您可以选择现有策略,也可以通过选择要创建的策略类型来创建新策略。
  • Decision Strategy

    此权限的决策策略。

6.1.2 资源权限类型

资源权限还可用于定义要应用于具有给定类型的所有资源的策略。
当您拥有共享公共访问要求和约束的资源时,这种基于资源的权限形式非常有用。

通常,应用程序中的资源可以根据它们封装的数据或它们提供的功能进行分类(或类型)。例如,财务应用程序可以管理不同的银行账户,其中每个账户属于特定客户。虽然它们是不同的银行账户,但它们共享由银行组织全球定义的共同安全要求和约束。使用资源权限类型,您可以定义要应用于所有银行帐户的公共策略,例如:

  • 只有所有者才能管理他的帐户
  • 仅允许所有者的国家/地区和/或地区访问
  • 执行特定的身份验证

要创建资源权限类型,请在创建新的基于资源的权限时单击“ Apply to Resource Type”。
通过将“Apply to Resource Type”设置为“On”,您可以指定要保护的类型以及要应用的策略,以管理对您指定类型的所有资源的访问。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

6.2 创建基于范围的权限

基于范围的权限定义一组一个或多个范围,以使用一组一个或多个授权策略进行保护。与基于资源的权限不同,您可以使用此权限类型不仅为资源创建权限,还为与其关联的作用域创建权限,在定义管理资源的权限以及可对其执行的操作时提供更多粒度。

要创建新的基于范围的权限,请在权限列表右上角的下拉列表中选择“Scope-based”。

Add Scope-Based Perission
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

6.2.1 配置

  • Name

    权限名称
  • Description

    权限描述
  • Resource

    将范围限制为与所选资源关联的范围。
    如果未选择任何选项,则所有范围均可用。
  • Apply Policy

    定义一组与权限关联的一个或多个策略。要关联策略,您可以选择现有策略,也可以通过选择要创建的策略类型来创建新策略。
  • Decision Strategy

    决策策略

6.2 决策策略

  • Unanimous

    默认策略(如果未提供)。一致的,所有的策略都必须决策通过,最终决策通过.
  • Affirmative

    肯定的, 只要有一项策略决策通过, 最终则决策通过
  • Consensus

    共识, 当决策通过的数量大于或等于决策不同过的策略, 则最终决策通过, 反之不通过

7. 评估、测试策略

在设计策略时,您可以模拟授权请求以测试策略的评估方式。

可以通过单击“Evaluate”选项卡来访问策略评估工具。在那里,您可以指定不同的输入来模拟真实的授权请求并测试策略的效果。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

7.1 Providing Identity Information

身份信息过滤器可用于指定请求权限的用户

7.2 Providing Contextual Information

上下文信息过滤器可用于为评估上下文定义其他属性,以便策略可以获取这些相同的属性。

7.3 Providing the Permissions

权限过滤器可用于构建授权请求。您可以为一组一个或多个资源和范围请求权限。如果要基于所有受保护资源和作用域模拟授权请求,请单击“添加”,而不指定任何“资源”或“作用域”。

输入所需信息后,单击“Evaluate”。

8. 授权服务

Keycloak授权服务建立在众所周知的标准之上,例如OAuth2和用户管理访问规范。

OAuth2客户端(例如前端应用程序)可以使用令牌端点从服务器获取访问令牌,并使用这些相同的令牌来访问受资源服务器保护的资源(例如后端服务)。同样,Keycloak授权服务提供对OAuth2的扩展,以允许基于与所请求的资源或范围相关联的所有策略的处理来发布访问令牌。这意味着资源服务器可以根据服务器授予的权限强制访问其受保护资源,并由访问令牌持有。在Keycloak授权服务中,具有权限的访问令牌称为请求方令牌或简称RPT。

除了发布RPT之外,Keycloak授权服务还提供了一组RESTful端点,允许资源服务器管理其受保护的资源,范围,权限和策略,帮助开发人员将这些功能扩展或集成到他们的应用程序中,以支持细粒度的授权

8.1 发现授权服务端点和元数据

Keycloak提供了一个发现文档,客户可以从中获取与Keycloak授权服务交互的所有必要信息,包括端点位置和功能。

发现文件可以从以下获得:

curl -X GET \
  http://${host}:${port}/auth/realms/${realm}/.well-known/uma2-configuration
  
http://keycloak.cloud.artreedu.com:8000/auth/realms/demo-realm/.well-known/uma2-configuration
  • 1
  • 2
  • 3
  • 4
Discovery Document
{
    "issuer": "http://keycloak.cloud.artreedu.com:8000/auth/realms/demo-realm",
    "authorization_endpoint": "http://keycloak.cloud.artreedu.com:8000/auth/realms/demo-realm/protocol/openid-connect/auth",
    "token_endpoint": "http://keycloak.cloud.artreedu.com:8000/auth/realms/demo-realm/protocol/openid-connect/token",
    "token_introspection_endpoint": "http://keycloak.cloud.artreedu.com:8000/auth/realms/demo-realm/protocol/openid-connect/token/introspect",
    "end_session_endpoint": "http://keycloak.cloud.artreedu.com:8000/auth/realms/demo-realm/protocol/openid-connect/logout",
    "jwks_uri": "http://keycloak.cloud.artreedu.com:8000/auth/realms/demo-realm/protocol/openid-connect/certs",
    "grant_types_supported": [
        "authorization_code",
        "implicit",
        "refresh_token",
        "password",
        "client_credentials"
    ],
    "response_types_supported": [
        "code",
        "none",
        "id_token",
        "token",
        "id_token token",
        "code id_token",
        "code token",
        "code id_token token"
    ],
    "response_modes_supported": [
        "query",
        "fragment",
        "form_post"
    ],
    "registration_endpoint": "http://keycloak.cloud.artreedu.com:8000/auth/realms/demo-realm/clients-registrations/openid-connect",
    "token_endpoint_auth_methods_supported": [
        "private_key_jwt",
        "client_secret_basic",
        "client_secret_post",
        "client_secret_jwt"
    ],
    "token_endpoint_auth_signing_alg_values_supported": [
        "RS256"
    ],
    "scopes_supported": [
        "openid",
        "address",
        "email",
        "offline_access",
        "phone",
        "profile"
    ],
    "resource_registration_endpoint": "http://keycloak.cloud.artreedu.com:8000/auth/realms/demo-realm/authz/protection/resource_set",
    "permission_endpoint": "http://keycloak.cloud.artreedu.com:8000/auth/realms/demo-realm/authz/protection/permission",
    "policy_endpoint": "http://keycloak.cloud.artreedu.com:8000/auth/realms/demo-realm/authz/protection/uma-policy",
    "introspection_endpoint": "http://keycloak.cloud.artreedu.com:8000/auth/realms/demo-realm/protocol/openid-connect/token/introspect"
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • token_endpoint

    符合OAuth2标准的令牌端点,支持urn:ietf:params:oauth:grant-type:uma-ticket grant type。通过此端点,客户端可以发送授权请求并获取具有Keycloak授予的所有权限的RPT。

  • token_introspection_endpoint

    符合OAuth2的令牌自省端点,客户端可以使用该端点查询服务器以确定RPT的活动状态,并确定与令牌关联的任何其他信息,例如Keycloak授予的权限。

  • resource_registration_endpoint

    符合UMA的资源注册端点,资源服务器可以使用它来管理受保护的资源和范围。此端点在Keycloak中提供操作创建,读取,更新和删除资源和范围。

  • permission_endpoint

    符合UMA的权限端点,资源服务器可以使用它来管理权限故障单。此端点在Keycloak中提供操作创建,读取,更新和删除权限票证。

8.2 获取权限

要从Keycloak获取权限,您需要向令牌端点发送授权请求。因此,Keycloak将评估与所请求的资源和范围相关联的所有策略,并发出具有服务器授予的所有权限的RPT。

客户端使用以下参数将授权请求发送到令牌端点:

  • grant_type

    必须, 参数值必须为: urn:ietf:params:oauth:grant-type:uma-ticket.

  • ticket

    可选参数,作为UMA授权过程的一部分,客户端收到的最新许可票证。

  • claim_token

    可选参数,表示在评估所请求的资源和范围的权限时服务器应考虑的其他声明的字符串。此参数允许客户端将声明推送到Keycloak。有关所有支持的标记格式的更多详细信息,请参阅claim_token_format参数。

  • claim_token_format

    可选参数, 一个字符串,指示claim_token参数中指定的令牌的格式。

    Keycloak支持两种令牌格式:

    • urn:ietf:params:oauth:token-type:jwt
    • https://openid.net/specs/openid-connect-core-1_0.html#IDToken.urn:ietf:params:oauth:token-type:jwt

    format表示claim_token参数引用访问令牌。https://openid.net/specs/openid-connect-core-1_0.html#IDToken表示claim_token参数引用OpenID Connect ID令牌。

  • rpt

    可选参数, 先前发布的RPT,其权限也应该被评估并添加到新的RPT中。此参数允许拥有RPT的客户端执行增量授权,其中根据需要添加权限。

  • permission

    可选参数, 一个字符串,表示客户端正在寻求访问的一组一个或多个资源和范围。可以多次定义此参数,以便请求多个资源和范围的权限。此参数是urn的扩展名:ietf:params:oauth:grant-type:uma-ticket grant type,以允许客户端在没有许可权证的情况下发送授权请求。字符串的格式必须是:RESOURCE_ID#SCOPE_ID。例如:Resource A#Scope A,Resource A#Scope A,Scope B,Scope C,Resource A#Scope A.

  • audience

    可选参数, 客户端正在寻求访问的资源服务器的客户端标识符。
    如果定义了permission参数,则此参数是必需的。
    它作为Keycloak的提示,指示应评估权限的上下文。

  • response_include_resource_name

    可选参数.

    一个布尔值,指示服务器是否应将资源名称包含在RPT的权限中。如果为false,则仅包括资源标识符。

  • response_permissions_limit

    可选参数.

    一个整数N,它定义了RPT可以拥有的权限数量限制。与rpt参数一起使用时,只有最后N个请求的权限将保留在RPT中。

  • submit_request

    可选参数.

    一个布尔值,指示服务器是否应对权限票据引用的资源和作用域创建权限请求。
    此参数仅在与ticket参数一起用作UMA授权过程的一部分时才有效

  • response_mode

    可选参数.

    一个字符串值,指示服务器应如何响应授权请求。
    当您主要对整体决策或服务器授予的权限感兴趣而不是标准OAuth2响应时,此参数特别有用。
    可能的值是:

    • decision
      表示来自服务器的响应应仅通过返回具有以下格式的JSON来表示总体决策:
      {
          'result': true
      }
      
      • 1
      • 2
      • 3
      如果授权请求未映射到任何权限,则返回403 HTTP状态代码。
    • permissions
      指示来自服务器的响应应包含服务器授予的任何权限,方法是返回具有以下格式的JSON:
      [
          {
              'rsid': 'My Resource'
              'scopes': ['view', 'update']
          },
      
          ...
      ]
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      如果授权请求未映射到任何权限,则返回403 HTTP状态代码。

授权请求示例 - 客户端访问受保护的两个资源

curl -X POST \
  http://${host}:${port}/auth/realms/${realm}/protocol/openid-connect/token \
  -H "Authorization: Bearer ${access_token}" \
  --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \
  --data "audience={resource_server_client_id}" \
  --data "permission=Resource A#Scope A" \
  --data "permission=Resource B#Scope B"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

客户端正在寻求访问受资源服务器保护的任何资源和范围时的授权请求示例。

curl -X POST \
  http://${host}:${port}/auth/realms/${realm}/protocol/openid-connect/token \
  -H "Authorization: Bearer ${access_token}" \
  --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \
  --data "audience={resource_server_client_id}"
  • 1
  • 2
  • 3
  • 4
  • 5

作为授权过程的一部分,当客户端在从资源服务器接收到许可权证后寻求访问UMA受保护资源时的授权请求示例:

curl -X POST \
  http://${host}:${port}/auth/realms/${realm}/protocol/openid-connect/token \
  -H "Authorization: Bearer ${access_token}" \
  --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \
  --data "ticket=${permission_ticket}
  • 1
  • 2
  • 3
  • 4
  • 5

如果$ Keycloak评估过程导致发布权限,它会发出与其关联权限的RPT:

Keycloak使用RPT响应客户端

HTTP/1.1 200 OK
Content-Type: application/json
...
{
    "access_token": "${rpt}",
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

服务器的响应与使用其他授权类型时来自令牌端点的任何其他响应一样。可以从access_token响应参数获得RPT。如果客户端未获得授权,Keycloak将使用403 HTTP状态代码进行响应:

keycloak 拒绝授权请求

HTTP/1.1 403 Forbidden
Content-Type: application/json
...
{
    "error": "access_denied",
    "error_description": "request_denied"
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

8.2.1 客户端验证方法

客户端需要对令牌端点进行身份验证才能获得RPT。
使用 urn:ietf:params:oauth:grant-type:uma-ticketgrant type时,客户端可以使用以下任何一种身份验证方法:

  • 承载令牌(Bearer Token)


    客户端应将访问令牌作为HTTP授权标头中的承载凭证发送到令牌端点。


    示例:使用访问令牌对令牌端点进行身份验证的授权请求

    curl -X POST \
      http://${host}:${port}/auth/realms/${realm}/protocol/openid-connect/token \
      -H "Authorization: Bearer ${access_token}" \
      --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket"
    
    • 1
    • 2
    • 3
    • 4

    当客户端代表用户行事时,此方法特别有用。
    在这种情况下,承载令牌是先前由Keycloak向代表用户(或代表其自身)行事的某个客户发布的访问令牌。
    将考虑访问令牌表示的访问上下文来评估权限。

    例如,如果访问令牌是发给代表用户A的客户端A,则将根据用户A有权访问的资源和范围授予权限。

  • 客户端凭据(Client Credentials)

    客户端可以使用Keycloak支持的任何客户端身份验证方法。例如,client_id / client_secret或JWT。

    示例:使用客户端ID和客户端密钥对授权终结点进行身份验证的授权请求

    curl -X POST \
    http://${host}:${port}/auth/realms/${realm}/protocol/openid-connect/token \
    -H "Authorization: Basic cGhvdGg6L7Jl13RmfWgtkk==pOnNlY3JldA==" \
    --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket"
    
    • 1
    • 2
    • 3
    • 4

8.2.2 推送声明

从服务器获取权限时,您可以推送任意声明,以便在评估权限时将这些声明提供给您的策略。

如果要在不使用权限票证(UMA流)的情况下从服务器获取权限,则可以向令牌端点发送授权请求,如下所示:

curl -X POST \
  http://${host}:${port}/auth/realms/${realm}/protocol/openid-connect/token \
  --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \
  --data "claim_token=ewogICAib3JnYW5pemF0aW9uIjogWyJhY21lIl0KfQ==" \
  --data "claim_token_format=urn:ietf:params:oauth:token-type:jwt" \
  --data "client_id={resource_server_client_id}" \
  --data "client_secret={resource_server_client_secret}" \
  --data "audience={resource_server_client_id}"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

claim_token参数需要BASE64编码的JSON,其格式类似于以下示例:

{
    "organization" : ["acme"]
}
  • 1
  • 2
  • 3

格式需要一个或多个声明,其中每个声明的值必须是字符串数组。

Pushing Claims Using UMA
有关如何在使用UMA和权限票据时推送声明的更多详细信息,请查看Permission API

8.3 User-Managed Access(UMA)

Keycloak授权服务基于用户管理访问或简称UMA。 UMA是一种通过以下方式增强OAuth2功能的规范:

  • Privacy

    如今,随着越来越多的数据和设备可用并连接到云,用户隐私正成为一个巨大的问题。使用UMA和Keycloak,资源服务器可以增强其功能,以便根据用户定义的策略授予用户隐私,从而改善其资源的保护方式。

  • Party-to-Party Authorization

    资源所有者(例如:常规最终用户)可以管理对其资源的访问,并授权其他方(例如:常规最终用户)访问这些资源。这与OAuth2不同,OAuth2同意代表用户的客户端应用程序,允许UMA资源所有者以完全异步的方式同意访问其他用户。

  • Resource Sharing

    允许资源所有者管理其资源的权限,并决定谁可以访问特定资源以及如何访问。然后,Keycloak可以充当共享管理服务,资源所有者可以从中管理其资源。

Keycloak是符合UMA 2.0标准的授权服务器,可提供大多数UMA功能。

例如,考虑使用网上银行服务(资源服务器)的用户Alice(资源所有者)来管理他的银行账户(资源)。有一天,爱丽丝决定向会计专业人士鲍勃(请求方)开设银行账户。但是,Bob应该只能访问Alice的帐户(范围)。

作为资源服务器,网上银行服务必须能够保护Alice的银行账户。为此,它依赖于Keycloak资源注册端点在服务器中创建代表Alice的银行帐户的资源。

此时,如果Bob尝试访问Alice的银行帐户,则访问将被拒绝。
网上银行服务为银行账户定义了一些默认政策。
其中之一是只允许所有者(在本例中为Alice)访问她的银行帐户。

但是,有关Alice隐私的网上银行服务也允许她更改银行账户的具体政策。她可以更改的其中一项政策是定义允许哪些人查看她的银行帐户。为此,网上银行服务依靠Keycloak向Alice提供一个空间,在那里她可以选择个人以及允许他们访问的操作(或数据)。在任何时候,Alice都可以撤销访问权限或向Bob授予其他权限。

8.3.1 授权流程

在UMA中,授权过程在客户端尝试访问受UMA保护的资源服务器时启动。

受UMA保护的资源服务器期望令牌中的承载令牌,其中令牌是RPT。当客户端在没有权限票证的情况下在资源服务器上请求资源时:

客户端在不发送RPT的情况下请求受保护资源

curl -X GET \
  http://${host}:8080/my-resource-server/resource/1bfdfe78-a4e1-4c2d-b142-fc92b75b986f
  • 1
  • 2

资源服务器使用权限ticket和as_uri参数向客户端发送响应,该参数具有Keycloak服务器的位置,应该将票证发送到该服务器以获取RPT。

资源服务器使用权限票据进行响应

HTTP/1.1 401 Unauthorized
WWW-Authenticate: UMA realm="${realm}",
    as_uri="https://${host}:${post}/auth/realms/${realm}",
    ticket="016f84e8-f9b9-11e0-bd6f-0021cc6004de"
  • 1
  • 2
  • 3
  • 4

权限票证是Keycloak Permission API发出的特殊类型的令牌。它们代表所请求的权限(例如:资源和范围)以及与请求相关的任何其他信息。只允许资源服务器创建这些令牌。

既然客户端具有许可权证以及Keycloak服务器的位置,则客户端可以使用发现文档来获取令牌端点的位置并发送授权请求。

客户端向令牌端点发送授权请求以获取RPT

curl -X POST \
  http://${host}:${port}/auth/realms/${realm}/protocol/openid-connect/token \
  -H "Authorization: Bearer ${access_token}" \
  --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \
  --data "ticket=${permission_ticket}
  • 1
  • 2
  • 3
  • 4
  • 5

如果$ Keycloak评估过程导致发布权限,它会发出与其关联权限的RPT:

Keycloak使用RPT响应客户端

HTTP/1.1 200 OK
Content-Type: application/json
...
{
    "access_token": "${rpt}",
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

服务器的响应与使用其他授权类型时来自令牌端点的任何其他响应一样。可以从access_token响应参数获得RPT。如果客户端未被授权拥有权限,Keycloak将使用403 HTTP状态代码进行响应:

Keycloak拒绝授权请求

HTTP/1.1 403 Forbidden
Content-Type: application/json
...
{
    "error": "access_denied",
    "error_description": "request_denied"
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

8.3.2 提交权限请求

作为授权过程的一部分,客户端首先需要从受UMA保护的资源服务器获取许可权证,以便与Keycloak令牌端点上的RPT进行交换。

默认情况下,在客户端无法获得RPT时Keycloak会响应403 HTTP状态代码和request_denied错误

HTTP/1.1 403 Forbidden
Content-Type: application/json
...
{
    "error": "access_denied",
    "error_description": "request_denied"
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

此类响应表示Keycloak不能颁发RPT给权限票据所代表的权限

在某些情况下,客户端应用程序可能希望启动异步授权流程,并让所请求资源的所有者决定是否应授予访问权限。为此,客户端可以使用submit_request请求参数以及对令牌端点的授权请求:

curl -X POST \
  http://${host}:${port}/auth/realms/${realm}/protocol/openid-connect/token \
  -H "Authorization: Bearer ${access_token}" \
  --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \
  --data "ticket=${permission_ticket} \
  --data "submit_request=true"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

使用submit_request参数时,Keycloak将为拒绝访问的每个资源保留一个权限请求。创建后,资源所有者可以检查其帐户并管理其权限请求。

您可以将此功能视为应用程序中的“请求访问”按钮,用户可以在其中要求其他用户访问其资源。

8.3.3 管理用户对资源的访问

用户可以使用Keycloak用户帐户服务管理对其资源的访问。要启用此功能,必须首先为您的领域启用用户管理的访问权限。为此,请在Keycloak管理控制台中打开领域设置页面并启 User-Managed Access switch。
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在左侧菜单中,“我的资源”选项指向用户可以执行以下操作的页面:

  • 管理需要我批准的权限请求(Need My approval)

    此部分包含等待批准的所有权限请求的列表。这些请求连接到请求访问特定资源的各方(用户)。允许用户批准或拒绝这些请求。

  • 管理我的资源(My resources)

    此部分包含用户拥有的所有资源的列表。用户可以单击资源以获取更多详细信息,并与其他人共享资源。

  • 管理共享给我的资源

    此部分包含与用户共享的所有资源的列表。

  • 管理正在等待批准的权限申请
    此部分包含用户发送的等待另一个用户或资源所有者批准的权限请求列表。

当用户通过单击“My resources”列表中的任何资源选择详细显示其资源时,他将重定向到页面,如下所示:
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 管理有权访问资源的人员

    此部分包含有权访问资源的人员列表。允许用户通过单击“撤消”按钮或删除特定权限来撤消访问权限。

  • 共享资源给其他人

    通过键入其他用户的用户名或电子邮件,用户可以共享资源并选择他要授予访问权限。

8.4 Protection API

Protection API提供符合UMA标准的端点集,提供:

  • 资源管理

    使用此端点,资源服务器可以远程管理其资源,并使策略实施者能够向服务器查询需要保护的资源。

  • 权限管理

    在UMA协议中,资源服务器访问此端点以创建权限票证。 Keycloak还提供端点来管理权限和查询权限的状态。

  • Policy API

    Keycloak利用UMA Protection API允许资源服务器管理其用户的权限。除了资源和权限API之外,Keycloak还提供了一个Policy API,资源服务器可以代表其用户将权限设置为资源。

这个API的一个重要需求是,只有资源服务器被允许使用一个特殊的OAuth2访问令牌(Protection API token(PAT))访问其端点。在UMA中,PAT是具有范围uma_protection的令牌。

8.4.1 PAT是什么?怎么获取?

protection API token(PAT) 是一个特殊的 OAuth2 access token, 其范围定义为uma_protection。
创建资源服务器时,Keycloak会自动为相应的客户端应用程序创建角色uma_protection,并将其与客户端的服务帐户相关联。

授予uma_protection角色的服务帐户
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

资源服务器可以像任何其他OAuth2访问令牌一样从Keycloak获取PAT。例如,使用curl:

curl -X POST \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -d 'grant_type=client_credentials&client_id=${client_id}&client_secret=${client_secret}' \
    "http://localhost:8080/auth/realms/${realm_name}/protocol/openid-connect/token"
  • 1
  • 2
  • 3
  • 4

上面的示例使用client_credentials grant类型从服务器获取PAT。因此,服务器返回类似于以下内容的响应:

{
  "access_token": ${PAT},
  "expires_in": 300,
  "refresh_expires_in": 1800,
  "refresh_token": ${refresh_token},
  "token_type": "bearer",
  "id_token": ${id_token},
  "not-before-policy": 0,
  "session_state": "ccea4a55-9aec-4024-b11c-44f6f168439e"
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Keycloak可以通过不同方式验证您的客户端应用程序。为简单起见,此处使用client_credentials grant类型,这需要client_id和client_secret。您可以选择使用任何支持的身份验证方法。

8.4.2 管理资源

资源服务器可以使用符合UMA的端点远程管理其资源:

http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set
  • 1

此端点提供如下概述的操作(为清晰起见,省略了整个路径):

  • 创建资源集描述:POST / resource_set
  • 读取资源集描述:GET / resource_set / {_ id}
  • 更新资源集描述:PUT / resource_set / {_ id}
  • 删除资源集描述:DELETE / resource_set / {_ id}
  • 列出资源集描述:GET / resource_set

更多信息,参见: UMA Resource Registration API.

创建资源
curl -v -X POST \
  http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set \
  -H 'Authorization: Bearer '$pat \
  -H 'Content-Type: application/json' \
  -d '{
     "name":"Tweedl Social Service",
     "type":"http://www.example.com/rsrcs/socialstream/140-compatible",
     "icon_uri":"http://www.example.com/icons/sharesocial.png",
     "resource_scopes":[
         "read-public",
         "post-updates",
         "read-private",
         "http://www.example.com/scopes/all"
      ]
  }'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

默认情况下,资源的所有者是资源服务器。如果要定义其他所有者(例如特定用户),可以按如下方式发送请求:

curl -v -X POST \
  http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set \
  -H 'Authorization: Bearer '$pat \
  -H 'Content-Type: application/json' \
  -d '{
     "name":"Alice Resource",
     "owner": "alice"
  }'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

可以使用用户名或用户标识符设置属性所有者。

创建用户管理的资源
默认情况下,资源所有者无法通过用户帐户服务管理通过Protection API创建的资源。

要创建资源并允许资源所有者管理这些资源,您必须设置ownerManagedAccess属性,如下所示:

curl -v -X POST \
  http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set \
  -H 'Authorization: Bearer '$pat \
  -H 'Content-Type: application/json' \
  -d '{
     "name":"Alice Resource",
     "owner": "alice",
     "ownerManagedAccess": true
  }'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
更新资源
curl -v -X PUT \
  http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set/{resource_id} \
  -H 'Authorization: Bearer '$pat \
  -H 'Content-Type: application/json' \
  -d '{
     "_id": "Alice Resource",
     "name":"Alice Resource",
     "resource_scopes": [
        "read"
     ]
  }'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
删除资源
curl -v -X DELETE \
  http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set/{resource_id} \
  -H 'Authorization: Bearer '$pat
  • 1
  • 2
  • 3
查询资源
根据ID查询
http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set/{resource_id}
  • 1

根据名称查询

http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set?name=Alice Resource
  • 1

根据uri查询

http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set?uri=/api/alice
  • 1

根据所有者查询

http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set?owner=alice
  • 1

根据类型查询

http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set?type=albums
  • 1

根据范围查询

http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set?scope=read
  • 1

在查询服务器的权限时,请使用参数first和max results来限制结果

8.4.3 管理权限请求

使用UMA协议的资源服务器可以使用特定端点来管理权限请求。此端点提供符合UMA的流,用于注册权限请求和获取权限票证。

http://${host}:${port}/auth/realms/${realm_name}/authz/protection/permission
  • 1

Permission Ticket是表示权限请求的特殊安全令牌类型。根据UMA规范,许可权证是:

从授权服务器传递到资源服务器,从资源服务器传递到客户端,最终从客户端传送回授权服务器的关联句柄,以使授权服务器能够评估应用于请求的正确策略
授权数据。
  • 1
  • 2

在大多数情况下,您不需要直接处理此端点。Keycloak提供了一个策略实施器,为您的资源服务器启用UMA,以便它可以从授权服务器获取权限票证,将此票证返回到客户端应用程序,并根据最终请求方令牌(RPT)强制执行授权决策。

从Keycloak获取许可票证的过程由资源服务器而不是常规客户端应用程序执行,其中当客户端尝试访问受保护资源而没有访问资源的必要授权时获取许可票证。使用UMA时发布权限票证是一个重要方面,因为它允许资源服务器:

  • 从客户端摘要与资源服务器保护的资源相关联的数据
  • 注册Keycloak授权请求,这些请求可以在以后的工作流程中使用,以根据资源所有者的同意授予访问权限
  • 将资源服务器与授权服务器分离,并允许它们使用不同的授权服务器保护和管理其资源

许可证也有值得强调的重要方面:

  • 客户端无需了解授权数据如何与受保护资源相关联。Permission ticket 对客户完全不透明。
  • 客户端可以访问不同资源服务器上的资源,并受不同授权服务器的保护

这些只是UMA带来的一些好处,其中UMA的其他方面强烈基于许可票证,特别是关于隐私和用户控制的资源访问。

创建 Permission Ticket
curl -X POST \
  http://${host}:${port}/auth/realms/${realm_name}/authz/protection/permission \
  -H 'Authorization: Bearer '$pat \
  -H 'Content-Type: application/json' \
  -d '[
  {
    "resource_id": "{resource_id}",
    "resource_scopes": [
      "view"
    ]
  }
]'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

创建票证时,您还可以推送任意声明并将这些声明与票证相关联:

curl -X POST \
  http://${host}:${port}/auth/realms/${realm_name}/authz/protection/permission \
  -H 'Authorization: Bearer '$pat \
  -H 'Content-Type: application/json' \
  -d '[
  {
    "resource_id": "{resource_id}",
    "resource_scopes": [
      "view"
    ],
    "claims": {
        "organization": ["acme"]
    }
  }
]'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在评估与许可权证相关联的资源和范围的权限时,您的策略可以使用这些声明。

8.4.4 使用Policy API管理资源权限

Keycloak利用UMA Protection API允许资源服务器管理其用户的权限。
除了资源和权限API之外,Keycloak还提供了一个Policy API,资源服务器可以代表其用户将权限设置为资源。

Policy API可在以下位置获得:

http://${host}:${port}/auth/realms/${realm_name}/authz/protection/uma-policy/{resource_id}
  • 1

此API受承载令牌保护,该承载令牌必须表示用户授予资源服务器以代表其管理权限的同意。承载令牌可以是从令牌端点获得的常规访问令牌,使用:

  • 资源所有者密码凭据授予类型
  • 令牌交换,用于交换授予某个客户端(公共客户端)的访问令牌,以获取其中受众是资源服务器的令牌
将权限与资源关联
要将权限与特定资源相关联,您必须发送HTTP POST请求,如下所示:
curl -X POST \
  http://localhost:8180/auth/realms/photoz/authz/protection/uma-policy/{resource_id} \
  -H 'Authorization: Bearer '$access_token \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json' \
  -d '{
        "name": "Any people manager",
        "description": "Allow access to any people manager",
        "scopes": ["read"],
        "roles": ["people-manager"]
}'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在上面的示例中,我们创建了一个新权限并将其与resource_id表示的资源相关联,其中任何具有角色people-manager的用户都应该被授予read范围。

您还可以使用其他访问控制机制创建策略,例如使用组:

curl -X POST \
  http://localhost:8180/auth/realms/photoz/authz/protection/uma-policy/{resource_id} \
  -H 'Authorization: Bearer '$access_token \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json' \
  -d '{
        "name": "Any people manager",
        "description": "Allow access to any people manager",
        "scopes": ["read"],
        "groups": ["/Managers/People Managers"]
}'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

或者特定的用户:

curl -X POST \
  http://localhost:8180/auth/realms/photoz/authz/protection/uma-policy/{resource_id} \
  -H 'Authorization: Bearer '$access_token \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json' \
  -d '{
        "name": "Any people manager",
        "description": "Allow access to any people manager",
        "scopes": ["read"],
        "clients": ["my-client"]
}'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

或者使用Javascript自定义策略

curl -X POST \
  http://localhost:8180/auth/realms/photoz/authz/protection/uma-policy/{resource_id} \
  -H 'Authorization: Bearer '$access_token \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json' \
  -d '{
        "name": "Any people manager",
        "description": "Allow access to any people manager",
        "scopes": ["read"],
        "condition": "if (isPeopleManager()) {$evaluation.grant()}"
}'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

还可以设置这些访问控制机制的任何组合。

要更新现有权限,请发送HTTP PUT请求,如下所示:

curl -X PUT \
  http://localhost:8180/auth/realms/photoz/authz/protection/uma-policy/{permission_id} \
  -H 'Authorization: Bearer '$access_token \
  -H 'Content-Type: application/json' \
  -d '{
    "id": "21eb3fed-02d7-4b5a-9102-29f3f09b6de2",
    "name": "Any people manager",
    "description": "Allow access to any people manager",
    "type": "uma",
    "scopes": [
        "album:view"
    ],
    "logic": "POSITIVE",
    "decisionStrategy": "UNANIMOUS",
    "owner": "7e22131a-aa57-4f5f-b1db-6e82babcd322",
    "roles": [
        "user"
    ]
}'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
删除权限
要删除与资源关联的权限,请发送HTTP DELETE请求,如下所示: ``` curl -X DELETE \ http://localhost:8180/auth/realms/photoz/authz/protection/uma-policy/{permission_id} \ -H 'Authorization: Bearer '$access_token ```
查询权限
要查询与资源关联的权限,请发送HTTP GET请求,如下所示: ``` http://${host}:${port}/auth/realms/${realm}/authz/protection/uma-policy?resource={resource_id} ```

要查询给定名称的权限,请发送HTTP GET请求,如下所示:

http://${host}:${post}/auth/realms/${realm}/authz/protection/uma-policy?name=Any people manager
  • 1

要查询与特定范围关联的权限,请发送HTTP GET请求,如下所示:

http://${host}:${post}/auth/realms/${realm}/authz/protection/uma-policy?scope=read
  • 1

要查询所有权限,请发送HTTP GET请求,如下所示:

http://${host}:${post}/auth/realms/${realm}/authz/protection/uma-policy
  • 1

在查询服务器的权限时,请使用参数first和max results来限制结果。

8.5 请求方令牌(RPT)

请求方令牌(RPT)是使用JSON Web签名(JWS)进行数字签名的JSON Web令牌(JWT)。该令牌是基于以前由Keycloak向代表用户或代表其自身行事的特定客户发布的OAuth2访问令牌构建的。

解码RPT时,您会看到类似于以下内容的有效负载:

{
  "authorization": {
      "permissions": [
        {
          "resource_set_id": "d2fe9843-6462-4bfc-baba-b5787bb6e0e7",
          "resource_set_name": "Hello World Resource"
        }
      ]
  },
  "jti": "d6109a09-78fd-4998-bf89-95730dfd0892-1464906679405",
  "exp": 1464906971,
  "nbf": 0,
  "iat": 1464906671,
  "sub": "f1888f4d-5172-4359-be0c-af338505d86c",
  "typ": "kc_ett",
  "azp": "hello-world-authz-service"
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

通过此令牌,您可以从权限声明中获取服务器授予的所有权限。

另请注意,权限与您要保护的资源/作用域直接相关,并且与用于实际授予和颁发这些相同权限的访问控制方法完全分离。

8.5.2 获取关于RPT的信息

令牌内省本质上是一个OAuth2令牌内省兼容端点,您可以从中获取有关RPT的信息。

http://${host}:${port}/auth/realms/${realm_name}/protocol/openid-connect/token/introspect
  • 1

要使用此端点对RPT进行内省,您可以按如下方式向服务器发送请求:

curl -X POST \
    -H "Authorization: Basic aGVsbG8td29ybGQtYXV0aHotc2VydmljZTpzZWNyZXQ=" \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -d 'token_type_hint=requesting_party_token&token=${RPT}' \
    "http://localhost:8080/auth/realms/hello-world-authz/protocol/openid-connect/token/introspect"
  • 1
  • 2
  • 3
  • 4
  • 5

上面的请求使用HTTP BASIC并传递客户端的凭据(客户端ID和密码)来验证尝试内省令牌的客户端,但您可以使用Keycloak支持的任何其他客户端身份验证方法。

内省端点需要两个参数:

  • token_type_hint

    使用reques_party_token作为此参数的值,表示您要内省RPT。
  • token

    使用服务器在授权过程中返回的标记字符串作为此参数的值。

因此,服务器响应是:

{
  "permissions": [
    {
      "resource_id": "90ccc6fc-b296-4cd1-881e-089e1ee15957",
      "resource_name": "Hello World Resource"
    }
  ],
  "exp": 1465314139,
  "nbf": 0,
  "iat": 1465313839,
  "aud": "hello-world-authz-service",
  "active": true
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

如果RPT未激活,则返回此响应:

{
    "active": false
}
  • 1
  • 2
  • 3

8.5.3 每次我想反省RPT时是否需要调用服务器?

不会。就像Keycloak服务器发布的常规访问令牌一样,RPT也使用JSON Web令牌(JWT)规范作为默认格式。

这基本上是策略执行者所做的。
务必:

  • 验证RPT的签名(基于领域的公钥)
  • 根据exp,iat和aud声明查询令牌有效性

8.6 授权客户端Java API

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

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

8.6.1 Maven Dependency

<dependencies>
    <dependency>
        <groupId>org.keycloak</groupId>
        <artifactId>keycloak-authz-client</artifactId>
        <version>${KEYCLOAK_VERSION}</version>
    </dependency>
</dependencies>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

8.6.2 配置

keycloak.json

{
  "realm": "hello-world-authz",
  "auth-server-url" : "http://localhost:8080/auth",
  "resource" : "hello-world-authz-service",
  "credentials": {
    "secret": "secret"
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • realm(必需): 领域名称

  • auth-server-url(必需):
    Keycloak服务器的基本URL。所有其他Keycloak页面和REST服务端点都源于此。它通常采用https://host:port/auth格式。

  • resource(必需):
    应用程序的客户端ID。每个应用程序都有一个client-id,用于标识应用程序。

  • credentials(必需):

    指定应用程序的凭据。这是一个对象表示法,其中键是凭证类型,值是凭证类型的值。

8.6.3 创建授权客户端

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

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

8.6.4 获取用户权利

以下是说明如何获取用户权利的示例:

// create a new instance based on the configuration defined in keycloak-authz.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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

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

/ create a new instance based on the configuration defined in keycloak-authz.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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

8.6.5 使用Protection API 创建资源

// create a new instance based on the configuration defined in keycloak-authz.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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

8.6.6 自醒RPT

// create a new instance based on the configuration defined in keycloak-authz.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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

9. 策略执行者

策略执行点(PEP)是一种设计模式,因此您可以以不同的方式实现它。
Keycloak提供了为不同平台,环境和编程语言实现PEP的所有必要手段。
Keycloak授权服务提供RESTful API,并利用OAuth2授权功能使用集中授权服务器进行细粒度授权。

image

PEP负责执行Keycloak服务器的访问决策,通过评估与受保护资源相关的策略来做出这些决策。它充当应用程序中的过滤器或拦截器,以检查是否可以根据这些决策授予的权限来满足对受保护资源的特定请求。

根据您使用的协议强制执行权限。使用UMA时,策略实施者始终期望将RPT作为承载令牌,以便决定是否可以提供请求。这意味着客户端应首先从Keycloak获取RPT,然后再向资源服务器发送请求。

但是,如果您不使用UMA,还可以将常规访问令牌发送到资源服务器。在这种情况下,策略实施器将尝试直接从服务器获取权限。

如果您使用任何Keycloak OIDC适配器,则可以通过将以下属性添加到keycloak.json文件来轻松启用策略实施器:

keycloak.json

{
    "policy-enforcer": {}
}
  • 1
  • 2
  • 3

当您启用策略实施器时,所有发送应用程序的请求都会被截获,并且将根据Keycloak授予发出请求的标识的权限授予对受保护资源的访问权限。

策略实施与您的应用程序的路径以及使用Keycloak管理控制台为资源服务器创建的资源密切相关。默认情况下,在创建资源服务器时,Keycloak会为资源服务器创建默认配置,以便您可以快速启用策略实施。

9.1 配置

要为应用程序启用策略实施,请将以下属性添加到keycloak.json文件中:

keycloak.json

{
  "policy-enforcer": {}
}
  • 1
  • 2
  • 3

如果您想手动定义受保护的资源,或者更详细一点:

{
  "policy-enforcer": {
    "user-managed-access" : {},
    "enforcement-mode" : "ENFORCING"
    "paths": [
      {
        "path" : "/someUri/*",
        "methods" : [
          {
            "method": "GET",
            "scopes" : ["urn:app.com:scopes:view"]
          },
          {
            "method": "POST",
            "scopes" : ["urn:app.com:scopes:create"]
          }
        ]
      },
      {
        "name" : "Some Resource",
        "path" : "/usingPattern/{id}",
        "methods" : [
          {
            "method": "DELETE",
            "scopes" : ["urn:app.com:scopes:delete"]
          }
        ]
      },
      {
        "path" : "/exactMatch"
      },
      {
        "name" : "Admin Resources",
        "path" : "/usingWildCards/*"
      }
    ]
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

以下是每个配置选项的说明:

  • policy-enforcer

    指定用于定义策略实际实施方式的配置选项,以及可选择要保护的路径。如果未指定,策略实施器将向服务器查询与受保护资源服务器关联的所有资源。在这种情况下,您需要确保使用与要保护的路径匹配的URIS属性正确配置资源。

    • user-managed-access

      指定适配器使用UMA协议。如果指定,则适配器向服务器查询权限票证,并根据UMA规范将它们返回给客户端。如果未指定,策略实施器将能够基于常规访问令牌或RPT强制执行权限。在这种情况下,在令牌缺少权限时拒绝访问资源之前,策略实施器将尝试直接从服务器获取权限。

    • enforcement-mode

      指定策略的实施方式。

      • ENFORCING

        默认,即使没有与给定资源关联的策略,也会拒绝请求。
      • PERMISSIVE

        即使没有与给定资源关联的策略,也允许请求。
      • DISABLED

        完全禁用策略评估并允许访问任何资源。当强制模式为DISABLED时,应用程序仍然可以通过授权上下文获取Keycloak授予的所有权限
    • on-deny-redirect-to

      定义从服务器获取“access denied”消息时重定向客户端请求的URL。默认情况下,适配器使用403 HTTP状态代码进行响应。

    • path-cache

      定义策略实施者应如何跟踪应用程序中的路径与Keycloak中定义的资源之间的关联。需要缓存以通过缓存路径和受保护资源之间的关联来避免对Keycloak服务器的不必要请求。

      • lifespan

        定义条目应该过期的时间(以毫秒为单位)。如果未提供,则默认值为3000.可以设置小于或等于0的值以完全禁用缓存。
      • max-entries

        定义应保留在缓存中的条目限制。如果未提供,则默认值为1000。
    • paths

      指定要保护的路径。此配置是可选的。如果未定义,策略实施器将通过在Keycloak中获取您为应用程序定义的资源来发现所有路径,其中这些资源是使用表示应用程序中某些路径的URIS定义的。

      • name

        服务器上与给定路径关联的资源的名称。当与路径一起使用时,策略实施器会忽略资源的URIS属性并使用您提供的路径。

      • path

        (必需) 相对于应用程序上下文路径的URI。如果指定了此选项,则策略实施器将在服务器中查询具有相同值的URI的资源。目前支持路径匹配的非常基本的逻辑。有效路径的示例如下:

        • 通配符: /*
        • 后缀: /*.html
        • 包含路径: /path/*
        • 路径参数: /resource/{id}
        • 完全匹配: /resource
        • 模式: /{version}/resource,/api/{version}/resource,/api/{version}/resource/*
      • methods

        要保护的HTTP方法(例如,GET,POST,PATCH)以及它们如何与服务器中给定资源的范围相关联。

        • method

          http method
        • scopes

          一个字符串数组,其范围与方法相关联。将作用域与特定方法关联时,尝试访问受保护资源(或路径)的客户端必须提供一个RPT,该RPT授予对列表中指定的所有作用域的权限。例如,如果使用范围create定义POST方法,则RPT必须包含在对路径执行POST时授予对create范围的访问权限。
        • scopes-enforcement-mode

          一个字符串,引用与方法关联的作用域的强制模式。值可以是ALL或ANY。如果为ALL,则必须授予所有已定义的作用域,以便使用该方法访问资源。如果是,则应授予至少一个范围,以便使用该方法访问资源。默认情况下,强制模式设置为ALL。
      • enforcement-mode

        指定策略的实施方式。

        • ENFORCING

          (默认)即使没有与给定资源关联的策略,也会拒绝请求。
        • DISABLED
      • claim-information-point

        定义一组必须解析并推送到Keycloak服务器的一个或多个声明,以使这些声明可用于策略。有关详细信息,请参阅Claim Information Point。

    • lazy-load-paths

      指定适配器如何获取服务器以获取与应用程序中的路径关联的资源。如果为true,则策略实施器将根据请求的路径相应地按需获取资源。如果您不希望在部署期间从服务器获取所有资源(如果您没有提供路径),或者您只定义了一组子路径并希望按需获取其他资源,则此配置特别有用。

9.2 声明信息点

声明信息点(CIP)负责解决声明并将这些声明推送到Keycloak服务器,以便提供有关策略访问上下文的更多信息。
可以将它们定义为策略实施者的配置选项,以便解决来自不同来源的声明,例如:

  • HTTP请求(参数,标题,正文,标题等)
  • 外部HTTP服务
  • 配置中定义的静态值
  • 通过实施Claim Information Provider SPI的任何其他来源

在向Keycloak服务器推送声明时,策略不仅可以基于用户是谁,还可以根据给定事务的人员,内容,原因,时间,地点和内容来考虑上下文和内容。它完全是关于基于上下文的授权以及如何使用运行时信息来支持细粒度的授权决策。

9.2.1 从HTTP请求中获取信息

以下是几个示例,说明如何从HTTP请求中提取声明:

keycloak.json

"policy-enforcer": {
    "paths": [
      {
        "path": "/protected/resource",
        "claim-information-point": {
          "claims": {
            "claim-from-request-parameter": "{request.parameter['a']}",
            "claim-from-header": "{request.header['b']}",
            "claim-from-cookie": "{request.cookie['c']}",
            "claim-from-remoteAddr": "{request.remoteAddr}",
            "claim-from-method": "{request.method}",
            "claim-from-uri": "{request.uri}",
            "claim-from-relativePath": "{request.relativePath}",
            "claim-from-secure": "{request.secure}",
            "claim-from-json-body-object": "{request.body['/a/b/c']}",
            "claim-from-json-body-array": "{request.body['/d/1']}",
            "claim-from-body": "{request.body}",
            "claim-from-static-value": "static value",
            "claim-from-multiple-static-value": ["static", "value"],
            "param-replace-multiple-placeholder": "Test {keycloak.access_token['/custom_claim/0']} and {request.parameter['a']} "
          }
        }
      }
    ]
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

9.2.2 从外部HTTP服务获取信息

以下是几个示例,说明如何从外部HTTP服务中提取声明:

keycloak.json

"policy-enforcer": {
    "paths": [
      {
        "path": "/protected/resource",
        "claim-information-point": {
          "http": {
            "claims": {
              "claim-a": "/a",
              "claim-d": "/d",
              "claim-d0": "/d/0",
              "claim-d-all": ["/d/0", "/d/1"]
            },
            "url": "http://mycompany/claim-provider",
            "method": "POST",
            "headers": {
              "Content-Type": "application/x-www-form-urlencoded",
              "header-b": ["header-b-value1", "header-b-value2"],
              "Authorization": "Bearer {keycloak.access_token}"
            },
            "parameters": {
              "param-a": ["param-a-value1", "param-a-value2"],
              "param-subject": "{keycloak.access_token['/sub']}",
              "param-user-name": "{keycloak.access_token['/preferred_username']}",
              "param-other-claims": "{keycloak.access_token['/custom_claim']}"
            }
          }
        }
      }
    ]
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

9.2.3 静态声明

keycloak.json

"policy-enforcer": {
    "paths": [
      {
        "path": "/protected/resource",
        "claim-information-point": {
          "claims": {
            "claim-from-static-value": "static value",
            "claim-from-multiple-static-value": ["static", "value"],
          }
        }
      }
    ]
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

9.2.4 声明信息 Provider SPI

开发人员可以使用声明信息提供程序SPI来支持不同的声明信息点,以防内置提供程序没有一个足以满足其要求。

例如,要实现新的CIP提供程序,您需要实现org.keycloak.adapters.authorization.ClaimInformationPointProviderFactory和ClaimInformationPointProvider,并在应用程序的类路径中提供文件META-INF / services / org.keycloak.adapters.authorization.ClaimInformationPointProviderFactory。

例如:
org.keycloak.adapters.authorization.ClaimInformationPointProviderFactory:

public class MyClaimInformationPointProviderFactory implements ClaimInformationPointProviderFactory<MyClaimInformationPointProvider> {

    @Override
    public String getName() {
        return "my-claims";
    }

    @Override
    public void init(PolicyEnforcer policyEnforcer) {

    }

    @Override
    public MyClaimInformationPointProvider create(Map<String, Object> config) {
        return new MyClaimInformationPointProvider(config);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

每个CIP提供程序都必须与名称相关联,如上面MyClaimInformationPointProviderFactory.getName方法中所定义。该名称将用于将策略实施器配置中的claim-information-point部分的配置映射到实现。

处理请求时,策略实施器将调用MyClaimInformationPointProviderFactory.create方法以获取MyClaimInformationPointProvider的实例。调用时,为此特定CIP提供程序定义的任何配置(通过claim-information-point)将作为映射传递。

ClaimInformationPointProvider的示例:

public class MyClaimInformationPointProvider implements ClaimInformationPointProvider {

    private final Map<String, Object> config;

    public ClaimsInformationPointProvider(Map<String, Object> config) {
        this.config = config;
    }

    @Override
    public Map<String, List<String>> resolve(HttpFacade httpFacade) {
        Map<String, List<String>> claims = new HashMap<>();

        // put whatever claim you want into the map

        return claims;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

9.3 获取授权上下文

启用策略实施(enforcement)后,可以通过org.keycloak.AuthorizationContext获取从服务器获取的权限。此类提供了几种可用于获取权限的方法,并确定是否为特定资源或范围授予了权限。

获取Servlet容器中的授权上下文:

HttpServletRequest request = ... // obtain javax.servlet.http.HttpServletRequest
    KeycloakSecurityContext keycloakSecurityContext =
        (KeycloakSecurityContext) request.getAttribute(KeycloakSecurityContext.class.getName());
    AuthorizationContext authzContext =
        keycloakSecurityContext.getAuthorizationContext();
  • 1
  • 2
  • 3
  • 4
  • 5

有关如何获取KeycloakSecurityContext的更多详细信息,请参阅适配器配置。上面的示例应该足以在使用Keycloak支持的任何servlet容器运行应用程序时获取上下文。

授权上下文有助于您更好地控制服务器所做出的决策。
例如,您可以使用它来构建动态菜单,其中隐藏或显示项目,具体取决于与资源或范围关联的权限。

if (authzContext.hasResourcePermission("Project Resource")) {
    // user can access the Project Resource
}

if (authzContext.hasResourcePermission("Admin Resource")) {
    // user can access administration resources
}

if (authzContext.hasScopePermission("urn:project.com:project:create")) {
    // user can create new projects
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

AuthorizationContext代表Keycloak授权服务的主要功能之一。从上面的示例中,您可以看到受保护资源与管理它们的策略没有直接关联。

使用基于角色的访问控制(RBAC)考虑一些类似的代码:

if (User.hasRole('user')) {
    // user can access the Project Resource
}

if (User.hasRole('admin')) {
    // user can access administration resources
}

if (User.hasRole('project-manager')) {
    // user can create new projects
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

尽管两个示例都满足相同的要求,但它们以不同的方式实现。在RBAC中,角色仅隐式定义其资源的访问权限。使用Keycloak,您可以创建更易于管理的代码,无论您使用的是RBAC,基于属性的访问控制(ABAC)还是任何其他BAC变体,都可以直接关注您的资源。您是否拥有给定资源或范围的权限,或者您没有。

现在,假设您的安全要求已更改,除项目经理外,PMO还可以创建新项目。

安全要求会发生变化,但使用Keycloak时,无需更改应用程序代码即可满足新要求。一旦您的应用程序基于资源和范围标识符,您只需更改与授权服务器中的特定资源关联的权限或策略的配置。在这种情况下,将更改与项目资源和/或作用域urn:project.com:project:create关联的权限和策略。

9.4 使用AuthorizationContext获取授权客户端实例

AuthorizationContext还可用于获取对应用程序配置的Authorization Client API的引用

ClientAuthorizationContext clientContext = ClientAuthorizationContext.class.cast(authzContext);
AuthzClient authzClient = clientContext.getClient();
  • 1
  • 2

在某些情况下,受策略实施者保护的资源服务器需要访问授权服务器提供的API。有了AuthzClient实例,资源服务器可以与服务器交互,以便以编程方式创建资源或检查特定权限。

9.5 Javascript集成

Keycloak Server附带了一个JavaScript库,您可以使用该库与受策略实施者保护的资源服务器进行交互。此库基于Keycloak JavaScript适配器,可以集成该适配器以允许客户端从Keycloak Server获取权限。

您可以通过在网页中包含以下脚本标记从运行Keycloak Server实例获取此库:

<script src="http://.../auth/js/keycloak-authz.js"></script>
  • 1

完成后,您可以创建KeycloakAuthorization实例,如下所示:

var keycloak = ... // obtain a Keycloak instance from keycloak.js library
var authorization = new KeycloakAuthorization(keycloak);
  • 1
  • 2

keycloak-authz.js库提供了两个主要功能:

  • 如果要访问受UMA保护的资源服务器,请使用权限票证从服务器获取权限。
  • 通过发送应用程序想要访问的资源和范围从服务器获取权限。

在这两种情况下,库都允许您轻松地与资源服务器和Keycloak授权服务进行交互,以获取具有客户端可用作承载令牌的权限的令牌,以访问资源服务器上的受保护资源。

9.5.1 处理受UMA保护的资源服务器的授权响应

如果资源服务器受策略实施器保护,它将根据随承载令牌携带的权限来响应客户端请求。
通常,当您尝试使用缺少访问受保护资源的权限的承载令牌访问资源服务器时,资源服务器将使用401状态代码和WWW-Authenticate标头进行响应。

HTTP/1.1 401 Unauthorized
WWW-Authenticate: UMA realm="${realm}",
    as_uri="https://${host}:${post}/auth/realms/${realm}",
    ticket="016f84e8-f9b9-11e0-bd6f-0021cc6004de"
  • 1
  • 2
  • 3
  • 4

有关更多信息,请参阅UMA授权过程。

您的客户端需要做的是从资源服务器返回的WWW-Authenticate标头中提取许可权证,并使用该库发送授权请求,如下所示:

// prepare a authorization request with the permission ticket
var authorizationRequest = {};
authorizationRequest.ticket = ticket;

// send the authorization request, if successful retry the request
Identity.authorization.authorize(authorizationRequest).then(function (rpt) {
    // onGrant
}, function () {
    // onDeny
}, function () {
    // onError
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

authorize函数是完全异步的,并支持一些回调函数来接收来自服务器的通知:

  • onGrant: 函数的第一个参数。如果授权成功并且服务器返回具有所请求权限的RPT,则回调接收RPT。
  • onDeny: 函数的第二个参数。仅在服务器拒绝授权请求时才调用。
  • onError: 函数的第三个参数。仅在服务器意外响应时才调用。

大多数应用程序应使用onGrant回调在401响应后重试请求。后续请求应包括RPT作为重试的承载令牌。

9.5.2 获取授权

keycloak-authz.js库提供了一个授权功能,您可以通过提供客户端想要访问的资源和范围来从服务器获取RPT。

有关如何获取具有用户可以访问的所有资源和范围的权限的RPT的示例

authorization.entitlement('my-resource-server-id').then(function (rpt) {
    // onGrant callback function.
    // If authorization was successful you'll receive an RPT
    // with the necessary permissions to access the resource server
});
  • 1
  • 2
  • 3
  • 4
  • 5

有关如何获取具有特定资源和范围权限的RPT的示例

authorization.entitlement('my-resource-server', {
    "permissions": [
        {
            "id" : "Some Resource"
        }
    ]
}).then(function (rpt) {
    // onGrant
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

使用授权功能时,必须提供要访问的资源服务器的client_id。

授权功能是完全异步的,并支持一些回调函数来接收来自服务器的通知:

  • onGrant:函数的第一个参数。如果授权成功并且服务器返回具有所请求权限的RPT,则回调接收RPT。
  • onDeny:函数的第二个参数。仅在服务器拒绝授权请求时才调用。
  • onError:函数的第三个参数。仅在服务器意外响应时才调用。

9.5.3 授权请求

authorizeentitlement函数都接受授权请求对象。可以使用以下属性设置此对象:

  • permissions

    表示资源和范围的对象数组。例如

    var authorizationRequest = {
       "permissions": [
           {
               "id" : "Some Resource",
               "scopes" : ["view", "edit"]
           }
       ]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • metadata

    一个对象,其属性定义服务器应如何处理授权请求。

    • response_include_resource_name

      一个布尔值,指示服务器是否应将资源名称包含在RPT的权限中。如果为false,则仅包括资源标识符。
    • response_permissions_limit

      一个整数N,它定义了RPT可以拥有的权限数量限制。与rpt参数一起使用时,只有最后N个请求的权限将保留在RPT中
  • submit_request

    一个布尔值,指示服务器是否应对权限票据引用的资源和作用域创建权限请求。此参数仅在与ticket参数一起用作UMA授权过程的一部分时生效。

9.5.4 获取RPT

如果您已使用库提供的任何授权函数获取了RPT,则始终可以从授权对象获取RPT,如下所示(假设它已通过前面介绍的技术之一进行了初始化):

var rpt = authorization.rpt;
  • 1

9.6 安装TLS/HTTPS

当服务器使用HTTPS时,请确保您的适配器配置如下:

{
  "truststore": "path_to_your_trust_store",
  "truststore-password": "trust_store_password"
}
  • 1
  • 2
  • 3
  • 4

上面的配置为授权客户端启用TLS / HTTPS,从而可以使用HTTPS方案远程访问Keycloak服务器。

强烈建议您在访问Keycloak Server端点时启用TLS / HTTPS。

https://www.keycloak.org/docs/latest/authorization_services/index.html#_enforcer_claim_information_point

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/684621
推荐阅读
相关标签
  

闽ICP备14008679号