Keycloak授权服务指南Authorization_services


版本10.0.0

本文来自官方文档 https://www.keycloak.org/docs/latest/authorization_services/ ,苦于国内根本打不开,并且英文不好理解,故提供一个不完全翻译版本作为参考。不准确之处,请自行查阅资料。

总览

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

  • 基于属性的访问控制(ABAC)
  • 基于角色的访问控制(RBAC)
  • 基于用户的访问控制(UBAC)
  • 基于上下文的访问控制(CBAC)
  • 基于规则的访问控制
    • 使用JavaScript
  • 基于时间的访问控制
  • 通过策略提供者服务提供者接口(SPI)支持自定义访问控制机制(ACM)

Keycloak基于一组管理UI和RESTful API,并提供了必要的方法来为受保护的资源和范围创建权限,将这些权限与授权策略相关联,并在应用程序和服务中实施授权决策。

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

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

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

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

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

架构

Keycloak AuthZ体系结构概述

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

  • 策略管理点(PAP)

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

  • 政策决策点(PDP)

    提供一个可分配的策略决策点,指向授权请求发送到的位置,并根据请求的权限对策略进行相应的评估。有关更多信息,请参见获取权限

  • 政策执行点(PEP)

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

  • 策略信息点(PIP)

    基于Keycloak Authentication Server,您可以在评估授权策略时从身份和运行时环境中获取属性。

授权过程

三个主要过程定义了必要的步骤,以了解如何使用Keycloak启用对应用程序的细粒度授权:

  • 资源管理
  • 权限和政策管理
  • 政策执行
资源管理

资源管理涉及定义保护对象的所有必要步骤。

资源管理概述

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

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

资源服务器概述

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

例如,您可能具有一个代表所有银行帐户的银行帐户资源,并使用它来定义所有银行帐户共有的授权策略。但是,您可能想为Alice帐户(属于客户的资源实例)定义特定策略,在该策略中,仅所有者被允许访问某些信息或执行操作。

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

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

权限和政策管理

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

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

权限和策略管理概述

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

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

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

定义策略后,就可以开始定义权限。权限与它们所保护的资源结合在一起。在这里,您可以指定要保护的内容(资源或范围)以及授予或拒绝权限必须满足的策略。

政策执行

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

PEP概述

Keycloak提供了一些内置的Policy Enforcer实施,您可以根据其运行的平台来保护应用程序。

授权服务

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

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

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

令牌端点

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

有关更多信息,请参见获取权限

保护API

保护API是一组UMA标准端点提供资源服务器操作,以帮助他们管理自己的资源,范围,权限和与它们相关的政策。仅允许资源服务器访问此API,这也需要 uma_protection范围。

Protection API提供的操作可以分为两个主要组:

  • 资源管理
    • 创建资源
    • 删除资源
    • 按ID查找
    • 询问
  • 权限管理
    • 发行许可票

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

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

有关更多信息,请参阅Protection API

术语

在继续之前,重要的是要了解Keycloak授权服务引入的这些术语和概念。

资源服务器Resource Server

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

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

在Keycloak中,任何机密的客户端应用程序都可以充当资源服务器。此客户的资源及其各自的范围受一组授权策略的保护和控制。

资源Resource

资源是应用程序和组织资产的一部分。它可以是一个或多个端点的集合,经典的Web资源(例如HTML页面)等等。在授权策略术语中,资源是受保护的对象

每个资源都有一个唯一的标识符,可以代表一个资源或一组资源。例如,您可以管理一个银行帐户资源,该资源代表并定义了所有银行帐户的一组授权策略。但是,您也可以使用名为Alice’s Banking Account的其他资源,该资源代表由单个客户拥有的单个资源,该资源可以具有自己的一组授权策略。

范围Scope

资源的范围是可以对资源执行的有限访问范围。在授权策略术语中,范围是可以在逻辑上应用于资源的潜在多个动词之一。

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

权限Permission

请考虑以下简单且非常常见的权限:

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

  • X CAN DO Y ON RESOURCE Z
    • 哪里…
      • X表示一个或多个用户,角色或组,或它们的组合。您还可以在此处使用声明和上下文。
      • Y代表要执行的动作,例如,写入,查看等。
      • Z表示受保护的资源,例如“ / accounts”。

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

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

政策Policy

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

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

政策提供者Policy Provider

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

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

许可证Permission Ticket

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

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

在UMA工作流中,权限票证是由授权服务器发布到资源服务器的,资源服务器将权限票证返回给尝试访问受保护资源的客户端。客户端收到票证后,就可以通过将票证发送回授权服务器来请求RPT(持有授权数据的最终令牌)。

有关许可票证的更多信息,请参阅用户管理的访问UMA规范。

入门

在使用本教程之前,您需要完成Keycloak的安装并创建初始管理员用户,如《入门指南》教程中所示。有一个警告。您必须在与Keycloak Server相同的计算机上运行一个单独的WildFly实例。这个单独的实例将运行您的Java Servlet应用程序。因此,您必须在其他端口下运行Keycloak,以便在同一台计算机上运行时不会出现端口冲突。jboss.socket.binding.port-offset在命令行上使用系统属性。此属性的值是一个数字,它将被添加到Keycloak Server打开的每个端口的基本值中。

要启动Keycloak服务器:

Linux / Unix

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

视窗

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

有关如何安装和配置WildFly的更多详细信息,请按照“ 保护应用程序和服务指南”教程中的步骤进行操作。

在安装和引导两个服务器之后,您应该能够访问位于http:// localhost:8180 / auth / admin /的 Keycloak管理控制台以及位于http:// localhost:8080的WildFly实例 。

保护Servlet应用程序

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

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

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

创建领域和用户

本教程的第一步是创建一个领域和该领域的用户。然后,在该领域内,我们将创建一个客户端应用程序,然后该客户端应用程序将成为资源服务器,您需要为其启用授权服务。

要创建领域和用户,请完成以下步骤:

  1. 创建一个名称为hello-world-authz的领域。创建后,将显示类似于以下内容的页面:

    领域hello-world-authz

    领域hello-world-authz

  2. 为您新创建的领域创建一个用户。单击用户。用户列表页面打开。

  3. 在空白用户列表的右侧,点击添加用户

  4. 要创建新用户,请完成UsernameEmailFirst NameLast Name字段。点击用户启用交换机,然后点击保存

    添加用户

    添加用户

  5. 通过单击“ 凭据”选项卡为用户设置密码。

    设置用户密码

    设置用户密码

  6. 使用密码填写“ 新密码”和“ 密码确认”字段,然后单击“ 临时”开关到“ 关闭”

  7. 单击“ 设置密码”以设置用户密码。

启用授权服务

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

要创建新客户端,请完成以下步骤:

  1. 单击“ 客户端”以开始创建新的客户端应用程序,并填写“ 客户端ID”,“ 客户端协议”和“ 根URL”字段。

    创建客户端应用程序

    创建客户端应用程序

  2. 点击保存。显示“客户详细信息”页面。

  3. 在“客户端详细信息”页面上,在“ 访问类型”字段中选择“ 机密 ” ,将“ 启用授权”开关更改为“ 开”,然后单击“ 保存”。将为客户端显示一个新的“ 授权”选项卡。

    客户资料

    客户资料

  4. 单击“ 授权”选项卡,显示类似于以下内容的“授权设置”页面:

    授权设定

    授权设定

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

有关授权配置的更多信息,请参阅启用授权服务

构建,部署和测试您的应用程序

现在,正确配置了app-authz-vanilla资源服务器(或客户端)并启用了授权服务,可以将其部署到服务器上。

Keycloak快速入门资料库中提供了要部署的应用程序的项目和代码。您需要在计算机上安装以下文件,并且在PATH中可用,然后才能继续:

  • Java JDK 8
  • Apache Maven 3.1.1或更高版本
  • Git

您可以通过在https://github.com/keycloak/keycloak-quickstarts克隆存储库来获取代码。快速入门旨在与最新的Keycloak版本一起使用。

请按照以下步骤下载代码。

克隆项目

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

我们将要构建和部署的应用程序位于

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

获取适配器配置

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

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

  1. 单击客户端。在客户端列表中,单击app-authz-vanilla客户端应用程序。将打开“客户端详细信息”页面。

    客户资料

    客户资料

  2. 单击安装选项卡。从格式选项下拉列表中,选择Keycloak OIDC JSON。适配器配置以JSON格式显示。点击下载

    适配器配置

    适配器配置

  3. 将文件移动keycloak.jsonapp-authz-jee-vanilla/config目录。

  4. (可选)默认情况下,403当用户缺乏访问资源服务器上受保护资源的权限时,策略执行器将以状态代码响应。但是,您也可以为未经授权的用户指定重定向URL。要指定重定向URL,请编辑在步骤3中更新的keycloak.json文件,并用policy-enforcer以下内容替换配置:

    1
    2
    3
    "policy-enforcer": {
    "on-deny-redirect-to" : "/app-authz-vanilla/error.jsp"
    }

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

构建和部署应用程序

要构建和部署应用程序,请执行以下命令:

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

测试应用

如果您的应用程序已成功部署,则可以访问http:// localhost:8080 / app-authz-vanilla。将打开“密钥克隆登录”页面。

登录页面

登录页面

使用您为该用户指定的密码以alice身份登录。认证后,显示以下页面:

Hello World Authz主页

Hello World Authz主页

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

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

您现在可以做很多事情来测试此应用程序。例如,您可以通过以下方法更改默认策略:单击客户端的“授权”选项Policies卡,然后单击选项卡,然后Default Policy在列表中单击以允许您按以下方式进行更改:

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

现在,退出演示应用程序,然后再次登录。您将无法再访问该应用程序。

拒绝访问页面

现在,Default Policy我们要解决此问题,但是除了更改代码外,我们将使用策略代码文本区域下方的下拉列表将更Logic改为Negative。当我们否定该策略的结果时,这将重新启用对应用程序的访问,默认情况下该策略将拒绝所有访问请求。同样,在测试此更改之前,请确保注销并再次登录。

下一步

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

  • 创建一个范围,为其定义策略和权限,然后在应用程序端对其进行测试。用户可以执行一项操作(或您创建的范围代表的其他任何操作)吗?
  • 创建不同类型的策略,例如基于JavaScript的策略,并将这些策略与关联Default Permission
  • 将多种策略应用于Default Permission并测试行为。例如,组合多个策略并相应地进行更改Decision Strategy
  • 有关如何在应用程序内部查看和测试权限的更多信息,请参见获取授权上下文

授权快速入门

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

授权快速入门经过设计,可以在不同的情况下以及使用不同的技术和集成来显示授权服务。它并不意味着涉及授权的所有可能用例的全面集合,但它们应为有兴趣了解如何在自己的应用程序中使用授权服务的用户提供一个起点。

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

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

管理资源服务器

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

在Keycloak中,资源服务器提供了一个丰富的平台,用于为其受保护的资源启用细粒度的授权,其中可以根据不同的访问控制机制来做出授权决策。

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

创建客户端应用程序

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

要创建客户端应用程序,请完成以下步骤:

  1. 单击客户端

    客户群

    客户群

  2. 在此页面上,点击创建

    创建客户

    创建客户

  3. 键入Client ID客户端。例如,my-resource-server

  4. 键入Root URL您的应用程序。例如:

    1
    http://${host}:${port}/my-resource-server
  5. 点击保存。创建客户端,并打开“客户端设置”页面。显示类似以下内容的页面:

    客户端设置

    客户端设置

启用授权服务

要将OIDC客户端应用程序转换为资源服务器并启用细粒度的授权,请选择机密**访问类型 ,然后将已启用授权的开关单击为开,然后单击保存**。

启用授权服务

启用授权服务

将为此客户端显示一个新的“授权”选项卡。单击授权选项卡,并显示类似于以下内容的页面:

资源服务器设置

资源服务器设置

Authorization(授权)选项卡包含其他子选项卡,涵盖了实际上必须保护应用程序资源所必须遵循的不同步骤。本文档中的特定主题分别覆盖了每个选项卡。但是这里是关于每个的简短描述:

  • 设定值

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

  • 资源资源

    在此页面上,您可以管理应用程序的资源

  • 授权范围

    在此页面上,您可以管理范围

  • 政策规定

    在此页面上,您可以管理授权策略并定义授予权限必须满足的条件。

  • 权限

    在此页面上,可以通过将受保护资源和范围与您创建的策略链接来管理这些权限

  • 评估

    在此页面上,您可以模拟授权请求并查看对已定义的权限和授权策略的评估结果。

  • 汇出设定

    从此页面,您可以授权设置导出到JSON文件。

资源服务器设置

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

  • 政策执行模式

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

    • 强制

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

    • 允许

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

    • 禁用

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

  • 决策策略

    此配置更改了策略评估引擎基于所有评估权限的结果来决定是否应授予资源或范围的方式。Affirmative意味着至少一个权限必须评估为肯定的决定,才能授予对资源及其范围的访问权限。Unanimous意味着所有权限都必须评估为肯定的决定,以便最终决定也为肯定的。例如,如果对同一资源或范围的两个许可权发生冲突(其中一个授予许可而另一个拒绝访问),则如果选择的策略为,则将授予对资源或作用域的许可Affirmative。否则,对任何权限的一个拒绝也将拒绝对资源或范围的访问。

  • 远程资源管理

    指定资源服务器是否可以远程管理资源。如果为false,则只能从管理控制台管理资源。

默认配置

编辑本节报告问题

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

默认配置包括:

  • 代表您应用程序中所有资源的默认受保护资源。
  • 始终授予对该策略保护的资源的访问权限的策略。
  • 一种权限,用于根据默认策略控制对所有资源的访问。

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

默认资源

默认资源

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

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

默认策略是唯一的领域策略,如果导航到“ 策略”选项卡,则可以查看默认策略。

默认策略

默认策略

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

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

最后,默认权限称为默认权限,如果您导航到“ 权限”选项卡,则可以查看默认权限

默认权限

默认权限

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

更改默认配置

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

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

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

导出和导入授权配置

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

  • 受保护的资源和范围
  • 政策规定
  • 权限

导出配置文件

要导出配置文件,请完成以下步骤:

  1. 导航到“ 资源服务器设置”页面。

  2. 单击导出设置选项卡。

  3. 在此页面上,点击导出

    汇出设定

    汇出设定

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

导入配置文件

要导入配置文件,请完成以下步骤:

  1. 导航到“ 资源服务器设置”页面。

    导入设置

    导入设置

要导入资源服务器的配置文件,请单击“ 选择文件”以选择一个包含要导入的配置的文件。

管理资源和范围

资源管理简单明了且通用。创建资源服务器之后,您可以开始创建要保护的资源和范围。可以分别导航到“ 资源”和“ 范围”选项卡来管理资源范围

查看资源

在“ 资源”页面上,您会看到与资源服务器关联的资源列表。

资源资源

资源资源

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

  • Type
  • URIS
  • Owner
  • 关联范围(或所有)
  • 相关权限

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

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

创建资源

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

要创建新资源,请单击资源列表右上角的“ 创建”

添加资源

添加资源

在Keycloak中,资源定义了不同类型的资源共有的一小部分信息,例如:

  • Name

    易于理解且独特的字符串,用于描述此资源。

  • Type

    一个字符串,唯一地标识一个或多个资源的集合的类型。该类型是用于对不同资源实例进行分组的字符串。例如,自动创建的默认资源的默认类型为urn:resource-server-name:resources:default

  • URIS

    提供资源位置/地址的URIS。对于HTTP资源,URIS通常是用于服务这些资源的相对路径。

  • Scopes

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

资源属性

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

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

分类资源

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

资源所有者

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

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

远程管理资源

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

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

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

管理政策

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

通过在编辑资源服务器时单击“ 策略”选项卡,可以查看与资源服务器关联的所有策略。

政策规定

政策规定

在此选项卡上,您可以查看先前创建的策略列表以及创建和编辑策略。

要创建新策略,请在策略列表的右上角,从Create policy下拉列表中选择一个策略类型。本节介绍有关每种策略类型的详细信息。

基于用户的策略

您可以使用这种类型的策略来定义权限的条件,其中允许一组一个或多个用户访问对象。

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

添加基于用户的策略

添加基于用户的策略

Configuration

  • 名称

    易读且唯一的字符串,用于标识策略。最佳做法是使用与您的业务和安全要求密切相关的名称,以便您可以更轻松地识别它们。

  • 描述

    包含有关此策略的详细信息的字符串。

  • 用户数

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

  • 逻辑

    在评估其他条件之后,将应用此策略的逻辑

基于角色的策略

您可以使用这种类型的策略来定义权限的条件,其中允许一组一个或多个角色访问对象。

默认情况下,未按要求指定添加到此策略的角色,并且如果已向请求访问的用户授予这些角色中的任何一个,则该策略将授予访问权限。但是,如果要强制执行特定角色,可以根据需要指定特定角色。您还可以组合必需和非必需角色,而不管它们是领域角色还是客户端角色。

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

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

添加基于角色的策略

添加基于角色的策略

Configuration

  • 名称

    易于理解且独特的字符串,用于描述策略。最佳做法是使用与您的业务和安全要求密切相关的名称,以便您可以更轻松地识别它们。

  • 描述

    包含有关此策略的详细信息的字符串。

  • 领域角色

    指定此策略允许哪些领域角色。

  • 客户角色

    指定此策略允许哪些客户端角色。要启用此字段,必须首先选择一个Client

  • 逻辑

    在评估其他条件之后,将应用此策略的逻辑

根据需要定义角色

创建基于角色的策略时,可以将特定角色指定为Required。当你这样做,该政策将授予访问权限只有在请求访问的用户已被授予所有需要的角色。领域和客户端角色都可以这样配置。

所需角色的示例

所需角色的示例

要根据需要指定角色,请选中Required要根据需要配置的角色的复选框。

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

基于JavaScript的策略

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

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

默认情况下,无法将JavaScript策略上载到服务器。您应该喜欢按照JavaScript Providers中的描述直接将JS策略部署到服务器。如果仍要使用Keycloak管理控制台来管理JS策略,则应启用该Upload Scripts功能。

添加JavaScript策略

添加JavaScript策略

组态

  • 名称

    易于理解且独特的字符串,用于描述策略。最佳做法是使用与您的业务和安全要求密切相关的名称,以便您可以更轻松地识别它们。

  • 描述

    包含有关此策略的详细信息的字符串。

  • JavaScript代码提供了此策略的条件。

  • 逻辑

    在评估其他条件之后,将应用此策略的逻辑

从已部署的JAR文件创建JS策略

Keycloak允许您部署JAR文件,以便将脚本部署到服务器。请查看JavaScript提供程序 以获取更多详细信息。

部署脚本后,应该可以从可用策略提供程序列表中选择部署的脚本。

例子

从评估上下文中检查属性

这是一个基于JavaScript的策略的简单示例,该策略使用基于属性的访问控制(ABAC)基于从执行上下文获得的属性来定义条件:

1
2
3
4
5
6
var context = $evaluation.getContext();
var contextAttributes = context.getAttributes();

if (contextAttributes.containsValue('kc.client.network.ip_address', '127.0.0.1')) {
$evaluation.grant();
}
从当前身份检查属性

这是一个基于JavaScript的策略的简单示例,该策略使用基于属性的访问控制(ABAC)基于与当前身份相关联的属性来定义条件:

1
2
3
4
5
6
7
8
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();
}

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

检查授予当前身份的角色

您还可以在策略中使用基于角色的访问控制(RBAC)。在下面的示例中,我们检查是否授予用户一个keycloak_user 领域角色:

1
2
3
4
5
6
var context = $evaluation.getContext();
var identity = context.getIdentity();

if (identity.hasRealmRole('keycloak_user')) {
$evaluation.grant();
}

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

1
2
3
4
5
6
var context = $evaluation.getContext();
var identity = context.getIdentity();

if (identity.hasClientRole('my-client', 'my-client-role')) {
$evaluation.grant();
}
检查授予用户的角色

要检查授予用户的领域角色:

1
2
3
4
5
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
6
7
8
9
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
var realm = $evaluation.getRealm();

if (realm.isUserInGroup('marta', '/Group A/Group B')) {
$evaluation.grant();
}
混合使用不同的访问控制机制

您也可以结合使用几种访问控制机制。下面的示例显示了如何在同一策略中使用角色(RBAC)和声明/属性(ABAC)检查。在这种情况下,我们检查是否授予用户admin角色或是否收到来自keycloak.org域的电子邮件:

1
2
3
4
5
6
7
8
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();
}
在编写自己的规则时,请记住$ evaluation对象是实现org.keycloak.authorization.policy.evaluation.Evaluation的对象。有关您可以从此界面访问的内容的更多信息,请参见评估API

基于时间的策略

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

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

添加时间政策

添加时间政策

Configuration

  • 名称

    易于理解且独特的字符串,用于描述策略。最佳做法是使用与您的业务和安全要求密切相关的名称,以便您可以更轻松地识别它们。

  • 描述

    包含有关此策略的详细信息的字符串。

  • 不早于

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

  • 不在或之后

    定义不允许授予访问权限的时间。仅当当前日期/时间早于或等于此值时,才授予权限。

  • 每月的一天

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

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

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

  • 小时

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

  • 分钟

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

  • 逻辑

    在评估其他条件之后,将应用此策略的逻辑

仅在满足所有条件的情况下才允许访问。Keycloak将根据每个条件的结果执行“ 与”操作

组合政策

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

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

添加汇总策略

添加汇总策略

假设您有一个名为“ 机密资源”的资源,该资源只能由keycloak.org域和特定IP地址范围内的用户访问。您可以同时创建两个条件的单个策略。但是,您想重用此策略的域部分以应用于无论原始网络如何都可运行的权限。

您可以为域和网络条件创建单独的策略,并基于这两个策略的组合创建第三个策略。使用聚合策略,您可以自由组合其他策略,然后将新的聚合策略应用于所需的任何权限。

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

组态

  • 名称

    易于理解且独特的字符串,用于描述策略。我们强烈建议您使用与您的业务和安全要求密切相关的名称,以便您可以更轻松地识别它们并知道它们的含义。

  • 描述

    一个包含有关此策略的更多详细信息的字符串。

  • 申请政策

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

  • 决策策略

    此权限的决策策略。

  • 逻辑

    在评估其他条件之后,将应用此策略的逻辑

综合政策的决策策略

创建汇总策略时,您还可以定义决策策略,该策略将用于基于每个策略的结果来确定最终决策。

  • 一致

    如果没有提供默认策略。在这种情况下,所有政策都必须评估为肯定的决定,最终决定也必须是肯定的。

  • 肯定

    在这种情况下,至少一项策略必须评估为肯定的决定,以便最终决定也为肯定的。

  • 共识

    在这种情况下,肯定决策的数量必须大于否定决策的数量。如果肯定和否定决定的数目相同,则最终决定将为否定。

基于客户的策略

编辑本节报告问题

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

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

添加基于客户端的策略

添加基于客户端的策略

组态

  • 名称

    易读且唯一的字符串,用于标识策略。最佳做法是使用与您的业务和安全要求密切相关的名称,以便您可以更轻松地识别它们。

  • 描述

    包含有关此策略的详细信息的字符串。

  • 客户群

    指定此策略授予哪些客户端访问权限。

  • 逻辑

    在评估其他条件之后,将应用此策略的逻辑

基于组的策略

编辑本节报告问题

您可以使用这种类型的策略来定义权限的条件,其中允许一组一个或多个组(及其层次结构)访问对象。

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

添加基于组的策略

添加基于组的策略

组态

  • 名称

    易于理解且独特的字符串,用于描述策略。最佳做法是使用与您的业务和安全要求密切相关的名称,以便您可以更轻松地识别它们。

  • 描述

    包含有关此策略的详细信息的字符串。

  • 团体索赔

    在包含组名和/或路径的令牌中指定声明的名称。通常,授权请求是基于先前发行给代表某些用户的客户端的ID令牌或访问令牌处理的。如果已定义,则令牌必须包含一项声明,该声明将从该策略中获取用户所属的组。如果未定义,则从您的领域配置中获取用户的组。

  • 团体

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

  • 逻辑

    在评估其他条件之后,将应用此策略的逻辑

扩展对子组的访问

编辑本节报告问题

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

在某些情况下,可能不仅需要允许访问组本身,而且还可以访问层次结构中的任何子组。对于添加的任何组,您可以选中复选框扩展到子组,以扩展对子组的访问。

扩展对子组的访问

扩展对子组的访问

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

正负逻辑

编辑本节报告问题

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

例如,假设您要创建一个策略,在该策略中,仅授予授予特定角色的用户访问权限。在这种情况下,您可以使用该角色创建基于角色的策略,并将其Logic字段设置为Negative。如果保留“ Positive ”(默认行为),则策略结果将保持原样。

政策评估API

编辑本节报告问题

使用JavaScript编写基于规则的策略时,Keycloak提供了评估API,该API提供有用的信息以帮助确定是否应授予许可。

该API包含一些接口,可让您访问信息,例如

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

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

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
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();
}

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

策略通过在实例上调用grant()or deny()方法来确定这一点Evaluation。默认情况下,Evaluation实例的状态被拒绝,这意味着您的策略必须显式调用该grant()方法以向策略评估引擎指示应授予权限。

有关评估API的更多信息,请参见JavaDocs

评价背景

评估环境为政策评估提供有用的信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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();
}

通过此接口,策略可以获得:

  • 认证的 Identity
  • 有关执行上下文和运行时环境的信息

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

EvaluationContext还让你访问有关双方的执行和运行时环境的属性。目前,只有一些内置属性。

名称 描述 类型
kc.time.date_time 当前日期和时间 串。格式MM/dd/yyyy hh:mm:ss
kc.client.network.ip_address 客户端的IPv4地址
kc.client.network.host 客户的主机名
kc.client.id 客户端ID
kc.client.user_agent “用户代理” HTTP标头的值 串[]
kc.realm.name 领域的名称

管理权限

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

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

权限

权限

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

  • 资源资源
  • 范围

要创建权限,请从权限列表右上角的下拉列表中选择要创建的权限类型。以下各节将更详细地介绍这两种类型的对象。

创建基于资源的权限

编辑本节报告问题

基于资源的权限定义了一组一个或多个资源,以使用一组一个或多个授权策略进行保护。

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

添加基于资源的权限

添加基于资源的权限

组态

  • 名称

    易于理解的,描述权限的字符串。最佳做法是使用与您的业务和安全要求密切相关的名称,以便您可以更轻松地识别它们。

  • 描述

    包含有关此权限的详细信息的字符串。

  • 应用于资源类型

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

    • 资源类型

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

  • 资源资源

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

  • 申请政策

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

  • 决策策略

    此许可的决策策略

键入资源权限

编辑本节报告问题

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

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

  • 只有所有者可以管理他的帐户
  • 仅允许来自所有者所在的国家和/或地区的访问
  • 强制执行特定的身份验证方法

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

类型化资源权限的示例

类型化资源权限的示例

创建基于范围的权限

编辑本节报告问题

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

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

添加基于范围的权限

添加基于范围的权限

组态

  • 名称

    易于理解的,描述权限的字符串。最佳做法是使用与您的业务和安全要求密切相关的名称,以便您可以更轻松地识别它们。

  • 描述

    包含有关此权限的详细信息的字符串。

  • 资源资源

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

  • 范围

    定义一组要保护的范围。

  • 申请政策

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

  • 决策策略

    此许可的决策策略

政策决策策略

编辑本节报告问题

将策略与权限相关联时,您还可以定义决策策略,以指定如何评估相关策略的结果以确定访问权限。

  • 一致

    如果没有提供默认策略。在这种情况下,所有政策都必须评估为肯定的决定,最终决定也必须是肯定的。

  • 肯定

    在这种情况下,至少一项政策必须评估为肯定的决定,最终决定也必须为肯定的。

  • 共识

    在这种情况下,肯定决策的数量必须大于否定决策的数量。如果肯定和否定决定的数量相等,则最终决定将为否定。

评估和测试政策

编辑本节报告问题

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

Evaluate编辑资源服务器时,可以通过单击选项卡来访问策略评估工具。您可以在此处指定不同的输入,以模拟实际的授权请求并测试策略的效果。

政策评估工具

提供身份信息

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

提供上下文信息

上下文信息过滤器可用于定义评估范围内的附加属性,使政策能够获得这些相同的属性。

提供权限

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

指定所需值后,点击评估

授权服务

编辑本节报告问题

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

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

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

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

编辑本节报告问题

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

可以从以下位置获取发现文档:

1
2
curl -X GET \
http://${host}:${port}/auth/realms/${realm}/.well-known/uma2-configuration

哪里${host}:${port}是哪里Keycloak运行和主机名(或IP地址)和端口${realm}是Keycloak一个领域的名称。

结果,您应该得到如下响应:

1
2
3
4
5
6
7
8
9
10
11
{

// some claims are expected here

// these are the main claims in the discovery document about Authorization Services endpoints location
"token_endpoint": "http://${host}:${port}/auth/realms/${realm}/protocol/openid-connect/token",
"token_introspection_endpoint": "http://${host}:${port}/auth/realms/${realm}/protocol/openid-connect/token/introspect",
"resource_registration_endpoint": "http://${host}:${port}/auth/realms/${realm}/authz/protection/resource_set",
"permission_endpoint": "http://${host}:${port}/auth/realms/${realm}/authz/protection/permission",
"policy_endpoint": "http://${host}:${port}/auth/realms/${realm}/authz/protection/uma-policy"
}

这些端点中的每个端点都具有一组特定的功能:

  • token_endpoint

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

  • token_introspection_endpoint

    客户端可以用来查询服务器以确定RPT的活动状态以及确定与令牌关联的任何其他信息(例如Keycloak授予的权限)的OAuth2兼容令牌自省端点。

  • resource_registration_endpoint

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

  • Permission_endpoint

    资源服务器可以使用UMA兼容的权限端点来管理权限票证。该端点提供了在Keycloak中创建,读取,更新和删除权限票证的操作。

取得权限

编辑本节报告问题

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

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

  • grant_type

    此参数是必需的。必须是urn:ietf:params:oauth:grant-type:uma-ticket

  • 此参数是可选的。客户端在UMA授权过程中收到的最新许可票。

  • Claim_token

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

  • Claim_token_format

    此参数是可选的。一个字符串,指示claim_token参数中指定的令牌的格式。Keycloak支持两种令牌格式:urn:ietf:params:oauth:token-type:jwthttps://openid.net/specs/openid-connect-core-1_0.html#IDToken。该urn:ietf:params:oauth:token-type:jwt格式表明该claim_token参数引用的访问令牌。的https://openid.net/specs/openid-connect-core-1_0.html#IDToken表示该 claim_token参数引用的ID连接ID令牌。

  • rpt

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

  • 允许

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

  • 听众

    此参数是可选的。客户端正在寻求访问的资源服务器的客户端标识符。如果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来表示整体决策:

      1
      2
      3
      {
      'result': true
      }

      如果授权请求未映射到任何权限,则将403返回HTTP状态代码。

    • permissions

      指示来自服务器的响应应包含服务器通过返回以下格式的JSON授予的任何权限:

      1
      2
      3
      4
      5
      6
      7
      8
      [
      {
      'rsid': 'My Resource'
      'scopes': ['view', 'update']
      },

      ...
      ]

      如果授权请求未映射到任何权限,则将403返回HTTP状态代码。

客户端寻求访问受资源服务器保护的两个资源时的授权请求示例。

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}" \
--data "permission=Resource A#Scope A" \
--data "permission=Resource B#Scope B"

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

1
2
3
4
5
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}"

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

1
2
3
4
5
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}

如果Keycloak评估过程导致了权限的颁发,它将发出与权限相关联的RPT:

Keycloak通过RPT响应客户端

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

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

Keycloak拒绝授权请求

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

客户端身份验证方法

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

  • 不记名令牌

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

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

    1
    2
    3
    4
    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"

    当客户端代表用户执行操作时,此方法特别有用。在这种情况下,承载令牌是Keycloak先前发给代表用户(或代表自身)行事的某些客户端的访问令牌。将考虑访问令牌代表的访问上下文来评估权限。例如,如果将访问令牌颁发给代表用户A的客户端A,则将根据用户A可以访问的资源和范围授予权限。

  • 客户凭证

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

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

    1
    2
    3
    4
    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"

推动索赔

编辑本节报告问题

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

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

1
2
3
4
5
6
7
8
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}"

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

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

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

使用UMA推送索赔

有关使用UMA和权限票证时如何提出声明的更多详细信息,请查看Permission API

用户管理的访问

编辑本节报告问题

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

  • 隐私

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

  • 党对党授权

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

  • 资源共享

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

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

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

作为资源服务器,Internet银行服务必须能够保护Alice的银行帐户。为此,它依靠Keycloak资源注册端点在服务器中创建一个代表Alice的银行帐户的资源。

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

但是,关于爱丽丝的隐私的网上银行服务也允许她更改银行帐户的特定政策。她可以更改的政策之一是定义允许哪些人查看她的银行帐户。为此,Internet Banking Service依靠Keycloak为Alice提供一个空间,让她可以选择个人以及允许他们访问的操作(或数据)。爱丽丝可以随时撤消访问权限或向鲍勃授予其他权限。

授权流程

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

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

客户端请求受保护的资源而不发送RPT

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

资源服务器将带有许可ticketas_uri参数的响应发送回客户端,该参数带有Keycloak服务器的位置,应该将票证发送到该位置,以便获得RPT。

资源服务器以权限票证响应

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

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

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

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

1
2
3
4
5
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}

如果Keycloak评估过程导致了权限的颁发,它将发出与权限相关联的RPT:

Keycloak通过RPT响应客户端

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

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

Keycloak拒绝授权请求

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

提交权限请求

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

默认情况下,如果无法为客户端颁发RPT ,则Keycloak会以403HTTP状态代码和request_denied错误响应。

Keycloak拒绝授权请求

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

这种响应意味着Keycloak无法使用权限票证所表示的权限来发布RPT。

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

1
2
3
4
5
6
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"

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

您可以将此功能视为Request Access应用程序中的按钮,用户可以在其中向其他用户请求访问其资源的权限。

管理对用户资源的访问

编辑本节报告问题

用户可以使用Keycloak用户帐户服务来管理对其资源的访问。要启用此功能,必须首先为您的领域启用“用户管理的访问”。为此,请在Keycloak管理控制台中打开领域设置页面,然后启用“用户管理的访问”开关。

我的资源

在左侧菜单上,该My Resources选项会转到一个页面,用户可以执行以下操作:

  • 管理需要我批准的权限请求

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

  • 管理我的资源

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

  • 管理与我共享的资源

    本节包含与用户共享的所有资源的列表。

  • 管理您的请求等待批准

    本节包含由用户发送的等待其他用户或资源所有者批准的许可请求列表。

当用户选择通过单击“我的资源”列表中的任何资源来详细说明自己的资源时,将其重定向到如下页面:

资源明细

通过此页面,用户可以:

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

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

  • 与他人共享资源

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

保护API

Protection API提供了符合UMA的一组端点,这些端点提供:

  • 资源管理

    使用此端点,资源服务器可以远程管理其资源,并使策略执行者可以查询服务器以获取需要保护的资源。

  • 权限管理

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

  • 政策API

    Keycloak利用UMA保护API允许资源服务器管理其用户的权限。除了资源和权限API外,Keycloak还提供了策略API,资源服务器可以从中代表用户为资源设置权限。

此API的一项重要要求是,允许资源服务器使用称为保护API令牌(PAT)的特殊OAuth2访问令牌访问其端点。在UMA中,PAT是范围为uma_protection的令牌。

什么是PAT以及如何获取

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

授予具有uma_protection角色的服务帐户

授予具有uma_protection角色的服务帐户

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

1
2
3
4
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"

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

1
2
3
4
5
6
7
8
9
10
{
"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"
}

Keycloak可以通过不同方式对客户端应用程序进行身份验证。为简单起见,此处使用client_credentials授予类型,该类型需要client_idclient_secret。您可以选择使用任何受支持的身份验证方法。

管理资源

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

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

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

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

有关每个操作的合同的更多信息,请参阅UMA Resource Registration API

创建资源

要创建资源,您必须发送HTTP POST请求,如下所示:

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":"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
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"
}'

owner可以使用用户名或用户标识符设置属性的位置。

创建用户管理的资源

默认情况下,资源保护者不能通过用户帐户服务来管理通过Protection API创建的资源。

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

1
2
3
4
5
6
7
8
9
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
}'
更新资源

要更新现有资源,请按以下方式发送HTTP PUT请求:

1
2
3
4
5
6
7
8
9
10
11
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"
]
}'
删除资源

要删除现有资源,请发送HTTP DELETE请求,如下所示:

1
2
3
curl -v -X DELETE \
http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set/{resource_id} \
-H 'Authorization: Bearer '$pat
查询资源

要通过查询资源id,请发送HTTP GET请求,如下所示:

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

要查询给定的资源name,请发送HTTP GET请求,如下所示:

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

要查询给定的资源uri,请发送HTTP GET请求,如下所示:

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

要查询给定的资源owner,请发送HTTP GET请求,如下所示:

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

要查询给定的资源type,请发送HTTP GET请求,如下所示:

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

要查询给定的资源scope,请发送HTTP GET请求,如下所示:

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

当查询服务器的权限时,请使用参数firstmax结果来限制结果。

管理权限请求

使用UMA协议的资源服务器可以使用特定的端点来管理权限请求。该端点提供了一个符合UMA的流程,用于注册许可请求并获得许可票证。

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

一个许可票是表示许可请求的特殊安全令牌类型。根据UMA规范,许可权证为:

1
A correlation handle that is conveyed from an authorization server to a resource server, from a resource server to a client, and ultimately from a client back to an authorization server, to enable the authorization server to assess the correct policies to apply to a request for authorization data.

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

从Keycloak获取许可权的过程是由资源服务器而不是常规的客户端应用程序执行的,当客户端尝试访问受保护的资源而无需访问资源的必要授权时,将获得许可权。使用UMA时,颁发许可票是一个重要方面,因为它允许资源服务器执行以下操作:

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

从客户的角度来看,许可凭单还具有重要的方面,值得强调:

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

这些只是UMA带来的部分好处,而UMA的其他方面则完全基于许可凭单,特别是关于隐私和用户对其资源的访问控制。

创建许可权证

要创建许可权票证,请按以下方式发送HTTP POST请求:

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"
]
}
]'

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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"]
}
}
]'

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

其他不符合UMA的端点
创建许可票

要将ID为{resource_id}的特定资源的权限授予ID为{user_id}的用户,作为资源所有者,发送HTTP POST请求,如下所示:

1
2
3
4
5
6
7
8
9
10
curl -X POST \
http://${host}:${port}/auth/realms/${realm_name}/authz/protection/permission/ticket \
-H 'Authorization: Bearer '$access_token \
-H 'Content-Type: application/json' \
-d '{
"resource": "{resource_id}",
"requester": "{user_id}",
"granted": true,
"scopeName": "view"
}'
获得许可票
1
2
curl http://${host}:${port}/auth/realms/${realm_name}/authz/protection/permission/ticket \
-H 'Authorization: Bearer '$access_token

您可以使用以下任何查询参数:

  • scopeId
  • resourceId
  • owner
  • requester
  • granted
  • returnNames
  • first
  • max
更新许可票
1
2
3
4
5
6
7
8
9
10
11
curl -X PUT \
http://${host}:${port}/auth/realms/${realm_name}/authz/protection/permission/ticket \
-H 'Authorization: Bearer '$access_token \
-H 'Content-Type: application/json' \
-d '{
"id": "{ticket_id}"
"resource": "{resource_id}",
"requester": "{user_id}",
"granted": false,
"scopeName": "view"
}'
删除许可票
1
2
curl -X DELETE http://${host}:${port}/auth/realms/${realm_name}/authz/protection/permission/ticket/{ticket_id} \
-H 'Authorization: Bearer '$access_token

使用策略API管理资源权限

Keycloak利用UMA保护API允许资源服务器管理其用户的权限。除了资源和权限API外,Keycloak还提供了策略API,资源服务器可以从中代表用户为资源设置权限。

可以在以下位置获得Policy API:

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

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

  • 资源所有者密码凭证授予类型
  • 令牌交换,以便将授予某些客户端(公共客户端)的访问令牌交换为以听众为资源服务器的令牌
将权限与资源相关联

要将权限与特定资源相关联,您必须发送HTTP POST请求,如下所示:

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"],
"roles": ["people-manager"]
}'

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

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

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"],
"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"]
}'

甚至使用JavaScript自定义策略:

上载脚本已弃用,在以后的版本中将被删除。默认情况下禁用此功能。要启用,请使用启动服务器 -Dkeycloak.profile.feature.upload_scripts=enabled 。有关更多详细信息,请参阅配置文件

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"],
"condition": "if (isPeopleManager()) {$evaluation.grant()}"
}'

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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"
]
}'
删除权限

要删除与资源关联的权限,请发送HTTP DELETE请求,如下所示:

1
2
3
curl -X DELETE \
http://localhost:8180/auth/realms/photoz/authz/protection/uma-policy/{permission_id} \
-H 'Authorization: Bearer '$access_token
查询权限

要查询与资源关联的权限,请发送HTTP GET请求,如下所示:

1
http://${host}:${port}/auth/realms/${realm}/authz/protection/uma-policy?resource={resource_id}

要查询给定名称的权限,请按以下方式发送HTTP GET请求:

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

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

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

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

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

当查询服务器的权限时,请使用参数firstmax结果来限制结果。

请求方令牌

请求方令牌(RPT)是使用JSON Web签名(JWS)进行数字签名的JSON Web令牌(JWT 。令牌是基于先前由Keycloak颁发给代表用户或代表自己的特定客户端的OAuth2访问令牌构建的。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"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"
}

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

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

内省请求方令牌

有时,您可能需要对请求方令牌(RPT)进行内部检查以检查其有效性,或获取令牌中的权限以在资源服务器端实施授权决策。

令牌自省可以在两种主要用例中为您提供帮助:

  • 当客户端应用程序需要查询令牌有效性以获取具有相同或其他权限的新令牌时
  • 在资源服务器端执行授权决策时,尤其是当没有内置策略实施者适合您的应用程序时

获取有关RPT的信息

令牌自省本质上是符合OAuth2令牌自省的终结点,您可以从中获取有关RPT的信息。

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

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

1
2
3
4
5
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"
上面的请求使用的是HTTP BASIC,并传递了客户端的凭据(客户端ID和密码)来对尝试自检令牌的客户端进行身份验证,但是您可以使用Keycloak支持的任何其他客户端身份验证方法。

内省端点需要两个参数:

  • token_type_hint

    使用requesting_party_token作为此参数的值,它表示您要对RPT进行内省。

  • 代币

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

结果,服务器响应为:

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"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
}

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

1
2
3
{
"active": false
}

每次想对RPT进行检查时都需要调用服务器吗?

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

如果要在不调用远程自省端点的情况下验证这些令牌,则可以解码RPT并在本地查询其有效性。解码令牌后,您还可以使用令牌中的权限来执行授权决策。

这实质上是策略执行者所做的。务必:

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

授权客户端Java API

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

它针对希望访问服务器提供的不同终结点的资源服务器,例如令牌终结点,资源和权限管理终结点。

Maven依赖

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

组态

客户端配置在keycloak.json文件中定义如下:

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

    领域的名称。

  • auth-server-url(必填)

    Keycloak服务器的基本URL。所有其他Keycloak页面和REST服务端点都从此派生。通常采用https:// host:port / auth的形式

  • 资源(必填)

    应用程序的客户端ID。每个应用程序都有一个用于标识该应用程序的客户端ID。

  • 凭据(必填)

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

配置文件通常位于应用程序的类路径中,这是客户端将尝试从中查找keycloak.json文件的默认位置。

创建授权客户端

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

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

获取用户权利

这是一个示例,说明如何获取用户权利:

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.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
15
16
17
// 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

使用保护API创建资源

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
// 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);

内省RPT

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 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);
}

政策执行者

编辑本节报告问题

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

PEP概述

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

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

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

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

keycloak.json

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

启用策略执行器后,将拦截应用程序发送的所有请求,并且将根据Keycloak对发出请求的身份授予的权限来授予对受保护资源的访问权限。

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

组态

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

keycloak.json

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

如果要手动定义受保护的资源,则更为冗长:

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": {
"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/*"
}
]
}
}

这是每个配置选项的描述:

  • 政策执行者

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

    • 用户管理的访问

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

    • 执法模式

      指定如何实施策略。

      • 执行力

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

      • 准许

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

      • 已停用

        完全禁用策略评估,并允许访问任何资源。如果enforcement-modeDISABLED 应用程序仍然能够通过获得由Keycloak授予的所有权限授权上下文

    • 拒绝重定向到

      定义一个URL,当从服务器获得“拒绝访问”消息时,会将客户端请求重定向到该URL。默认情况下,适配器以403 HTTP状态代码响应。

    • 路径缓存

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

      • 寿命

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

      • 最大条目

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

    • 路径

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

      • 名称

        服务器上与给定路径关联的资源的名称。与路径结合使用时,策略执行器将忽略资源的URIS属性,而使用您提供的路径。

      • 路径

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

        • 通配符: /*
        • 后缀: /*.html
        • 子路径: /path/*
        • 路径参数:/ resource / {id}
        • 完全匹配:/ resource
        • 模式:/ {版本} /资源,/ api / {版本} /资源,/ api / {版本} /资源/ *
      • 方法

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

        • 方法

          HTTP方法的名称。

        • 范围

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

        • 范围执行模式

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

      • 执法模式

        指定如何实施策略。

        • 执行力

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

        • 已停用

      • 索赔信息点

        定义一组一个或多个声明,必须解决这些声明并将其推送到Keycloak服务器,以使这些声明对策略可用。有关更多详细信息,请参见索赔信息点

    • 延迟加载路径

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

    • http-method-as-scope

      指定作用域应如何映射到HTTP方法。如果设置为true,则策略执行者将使用当前请求中的HTTP方法来检查是否应授予访问权限。启用后,请确保您在Keycloak中的资源与表示您要保护的每个HTTP方法的范围相关联。

    • 索赔信息点

      定义一组一个或多个全局声明,必须解决这些声明并将其推送到Keycloak服务器,以使这些声明对策略可用。有关更多详细信息,请参见索赔信息点

索赔信息点

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

  • HTTP请求(参数,标头,正文等)
  • 外部HTTP服务
  • 配置中定义的静态值
  • 通过实现声明信息提供者SPI的任何其他来源

将声明推送到Keycloak服务器时,策略不仅可以基于用户是谁,还可以基于上下文,内容,给定交易的对象,对象,原因,时间,地点以及对象来决定决策。这全部与基于上下文的授权有关,以及如何使用运行时信息以支持细粒度的授权决策。

从HTTP请求获取信息

以下是一些示例,展示了如何从HTTP请求中提取声明:

keycloak.json

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
"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']} "
}
}
}
]
}

从外部HTTP服务获取信息

以下是一些示例,显示了如何从外部HTTP服务提取声明:

keycloak.json

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
"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']}"
}
}
}
}
]
}

静态声明

keycloak.json

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

索赔信息提供者SPI

开发人员可以使用声明信息提供者SPI来支持不同的声明信息点,以防任何内置提供者不足以满足他们的要求。

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

范例org.keycloak.adapters.authorization.ClaimInformationPointProviderFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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);
}
}

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

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

范例ClaimInformationPointProvider

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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;
}
}

获取授权上下文

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

在Servlet容器中获取授权上下文

1
2
3
4
5
6
HttpServletRequest request = ... // obtain javax.servlet.http.HttpServletRequest
KeycloakSecurityContext keycloakSecurityContext =
(KeycloakSecurityContext) request
.getAttribute(KeycloakSecurityContext.class.getName());
AuthorizationContext authzContext =
keycloakSecurityContext.getAuthorizationContext();
有关如何获取详细信息,KeycloakSecurityContext请查阅适配器配置。上面的示例足以在使用Keycloak支持的任何servlet容器运行应用程序时获得上下文。

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

1
2
3
4
5
6
7
8
9
10
11
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
}

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

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

1
2
3
4
5
6
7
8
9
10
11
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
}

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

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

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

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

AuthorizationContext还可以用来获取到的参考授权客户端API配置到应用程序:

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

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

JavaScript整合

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

通过script在网页中包含以下标记,可以从正在运行的Keycloak Server实例中获取此库:

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

完成此操作后,您可以创建一个KeycloakAuthorization实例,如下所示:

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

keycloak-authz.js库提供了两个主要特点:

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

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

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

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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
// 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
});

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

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

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

获得权利

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

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

1
2
3
4
5
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
});

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

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

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

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

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

授权请求

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

  • 权限

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

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

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

    • response_include_resource_name

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

    • response_permissions_limit

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

  • Submit_request

    一个布尔值,指示服务器是否应该对许可权证所引用的资源和范围创建许可权请求。该参数仅在与ticketUMA授权过程中的参数一起使用时才生效。

获取RPT

如果您已经使用库提供的任何授权功能获得了RPT,则始终可以从授权对象中获取RPT,如下所示(假定它已通过前面显示的一种技术进行了初始化):

1
var rpt = authorization.rpt;

设置TLS / HTTPS

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

keycloak.json

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

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

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

最后更新时间2020-04-29 10:38:34 UTC


文章作者: KavenRan
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 KavenRan !
 上一篇
Knowage7汉化补丁全面升级支持Windows&Linux Knowage7汉化补丁全面升级支持Windows&Linux
版本支持Knowage中文汉化补丁全面升级, 支持最新稳定版 : Knowage-Server-7.1.7 功能支持 安装汉化 卸载汉化 使用步骤 下载汉化补丁: knowage-zh-7.1.7.zip 解压到To
2020-05-25
下一篇 
《从新冠肺炎疫情冲击看全球与中国经济发前景》学习笔记 《从新冠肺炎疫情冲击看全球与中国经济发前景》学习笔记
听了复旦大学经济学院院长张军关于《从新冠肺炎疫情冲击看全球与中国经济发前景》的演讲,进行学习总结。 引言:新冠疫情全球肆虐,对全球经济造成了严重的冲击,与此同时沙特、俄罗斯进行的原油价格战,成为压倒金融市场的最后一根稻草。 这一系列黑天鹅
2020-04-24
  目录