赞
踩
https://www.keycloak.org/docs/latest/authorization_services/index.html
Keycloak支持细粒度的授权策略,并且能够组合不同的访问控制机制,例如:
Keycloak基于一组管理UI和RESTful API,为受保护资源和作用域创建权限,将这些权限与授权策略相关联以及在应用程序和服务中强制执行授权决策的必要方法。
资源服务器(为受保护资源提供服务的应用程序或服务)通常依赖某种信息来决定是否应该向受保护资源授予访问权限。
对于基于RESTful的资源服务器,该信息通常从安全令牌获取,通常在每次请求发送到服务器时作为承载令牌发送。
对于依赖会话对用户进行身份验证的Web应用程序,该信息通常存储在用户的会话中,并从那里为每个请求检索。
通常,资源服务器仅基于基于角色的访问控制(RBAC)执行授权决策,其中,针对映射到这些相同资源的角色检查授予尝试访问受保护资源的用户的角色。
虽然角色非常有用并且被应用程序使用,但它们也有一些限制:
考虑到今天我们需要考虑用户分布在不同地区,不同本地策略,使用不同设备以及对信息共享的高需求的异构环境,Keycloak授权服务可以帮助您提高应用程序和服务的授权功能通过提供:
从设计角度来看,授权服务基于一组明确定义的授权模式,提供以下功能:
策略管理点(Policy Administration Point/PAP)
提供基于Keycloak管理控制台的一组UI,以管理资源服务器,资源,范围,权限和策略。部分内容也可以通过使用Protection API远程完成。
策略决策点(PDP)
提供可分发的策略决策点,指向发送授权请求的位置,并根据请求的权限相应地评估策略。有关更多信息,请参阅获取权限。
策略执行点(PEP)
提供不同环境的实现,以在资源服务器端实际执行授权决策。 Keycloak提供了一些内置的Policy Enforcer。
策略信息点(PIP)
基于Keycloak Authentication Server,可以从身份和运行时环境中获取属性。
主要步骤为三个流程,以了解如何使用Keycloak为您的应用程序启用细粒度授权:
首先,您需要指定Keycloak您希望保护的内容,通常代表Web应用程序或一组一个或多个服务。有关资源服务器的更多信息,请参阅术语。
使用Keycloak管理控制台管理资源服务器。在那里,您可以启用任何已注册的客户端应用程序作为资源服务器,并开始管理您要保护的资源和范围。
资源可以是网页,RESTFul资源,文件系统中的文件,EJB等。它们可以表示一组资源(就像Java中的类一样),也可以表示单个特定资源。
例如,您可能拥有代表所有银行账户的银行账户资源,并使用它来定义所有银行账户共有的授权策略。但是,您可能希望为Alice帐户(属于客户的资源实例)定义特定策略,其中只允许所有者访问某些信息或执行操作。
可以使用Keycloak管理控制台或Protection API管理资源。在后一种情况下,资源服务器能够远程管理其资源。
范围通常表示可以对资源执行的操作,但它们不限于此。您还可以使用范围来表示资源中的一个或多个属性。
此过程涉及实际定义管理资源的安全性和访问要求的所有必要步骤。
策略定义了访问或执行某些操作(资源或范围)必须满足的条件,但它们与它们保护的内容无关。
它们是通用的,可以重用来构建权限甚至更复杂的策略。
例如,要仅允许授予角色“User Premium”的用户访问一组资源,您可以使用RBAC(基于角色的访问控制)。
Keycloak提供了一些内置策略类型(及其各自的策略提供者),涵盖了最常见的访问控制机制。您甚至可以根据使用JavaScript或JBoss Drools编写的规则创建策略。
定义策略后,即可开始定义权限。
权限与他们保护的资源相结合。
在此处指定要保护的内容(资源或范围)以及授予或拒绝权限必须满足的策略。
Keycloak提供了一些内置的Policy Enforcer实现,您可以使用它们来保护您的应用程序,具体取决于它们运行的平台。
授权服务由以下RESTFul端点组成:
这些服务中的每一个都提供了一个特定的API,涵盖了授权过程中涉及的不同步骤。
同样,Keycloak授权服务提供对OAuth2的扩展,以允许基于与所请求的资源或范围相关联的所有策略的处理来发布访问令牌。
这意味着资源服务器可以根据服务器授予的权限强制访问其受保护资源,并由访问令牌持有。
在Keycloak授权服务中,具有权限的访问令牌称为请求方令牌或简称RPT。
更多信息,请参阅获取权限。
只允许资源服务器访问此API,这也需要uma_protection范围。
Protection API提供的操作可以分为两大类:
默认情况下,启用远程资源管理。您可以使用Keycloak管理控制台更改它,并且只允许通过控制台进行资源管理。
使用UMA协议时,Protection API发布权限票证是整个授权过程的重要部分。如后续部分所述,它们表示客户端请求的权限,并且发送到服务器以获取最终令牌,该最终令牌具有在评估与请求的资源和范围相关联的权限和策略期间授予的所有权限。
更多信息,请参阅Protection API。
资源服务器是托管受保护资源并能够接受和响应受保护资源请求的服务器
资源服务器通常依赖某种信息来决定是否应该授予对受保护资源的访问权限。
对于基于RESTful的资源服务器,该信息通常在安全令牌中携带,通常作为承载令牌以及每个请求发送到服务器。
依赖会话对用户进行身份验证的Web应用程序通常将该信息存储在用户的会话中,并从那里为每个请求检索它。
资源服务器通常依赖某种信息来决定是否应该授予对受保护资源的访问权限。
对于基于RESTful的资源服务器,该信息通常在安全令牌中携带,通常作为承载令牌以及每个请求发送到服务器。
依赖会话对用户进行身份验证的Web应用程序通常将该信息存储在用户的会话中,并从那里为每个请求检索它。
每个资源都有一个唯一标识符,可以表示单个资源或一组资源。
例如,您可以管理银行账户资源,该资源代表并定义所有银行账户的一组授权政策。
但您也可以使用名为Alice的银行账户的不同资源,该账户代表单个客户拥有的单一资源,该客户可以拥有自己的一组授权策略。
资源的范围是可以在资源上执行的有限访问范围。
在授权策略术语中,范围是可以逻辑地应用于资源的潜在许多动词之一。它通常表示可以使用给定资源执行的操作。
范围的示例包括查看,编辑,删除等。但是,范围也可以与资源提供的特定信息相关。在这种情况下,您可以拥有项目资源和成本范围,其中成本范围用于定义用户访问项目成本的特定策略和权限。
权限将受保护的对象与必须评估的策略相关联,以确定是否授予访问权限。
X CAN DO Y ON RESOURCE Z
Keycloak提供了一个丰富的平台,用于构建一系列权限策略,范围从简单到非常复杂,基于规则的动态权限。它提供了灵活性,有助于:
策略定义了授予对象访问权限必须满足的条件。与权限不同,您不指定要保护的对象,而是指定访问给定对象必须满足的条件(例如,资源,范围或两者)。策略与可用于保护资源的不同访问控制机制(ACM)密切相关。使用策略,您可以实施基于属性的访问控制(ABAC),基于角色的访问控制(RBAC),基于上下文的访问控制或这些的任意组合的策略。
Keycloak利用策略的概念以及如何通过提供聚合策略的概念来定义它们,您可以在其中构建“policy of policies”并仍然控制评估的行为。Keycloak授权服务中的策略实现遵循分而治之的技术,而不是编写一个具有访问给定资源必须满足的所有条件的大型策略。也就是说,您可以创建单独的策略,然后使用不同的权限重用它们,并通过组合各个策略来构建更复杂的策略。
策略提供者是特定策略类型的实现。Keycloak提供内置策略,由相应的策略提供商提供支持,您可以创建自己的策略类型以支持您的特定需求。
Keycloak提供了一个SPI(服务提供程序接口),您可以使用它来插入自己的策略提供程序实现。
权限票证是由 用户管理访问(UMA) 规范定义的特殊类型的令牌,其提供不透明结构,其形式由授权服务器确定。此结构表示客户端请求的资源和/或范围,访问上下文,以及必须应用于授权数据请求的策略(请求方令牌[RPT])。
在UMA中,许可票证对于支持人与人之间的共享以及人与组织之间的共享至关重要。使用授权工作流的权限票证可以实现从简单到复杂的一系列方案,其中资源所有者和资源服务器可以根据管理对这些资源的访问的细粒度策略完全控制其资源。
更多信息, 查阅UMA章节用户管理控制(User-Managed-Access)
首先需要安装keycloak
启动Keycloak Server
Linux/Unix
$ .../bin/standalone.sh -Djboss.socket.binding.port-offset=100
Windows
> ...\bin\standalone.bat -Djboss.socket.binding.port-offset=100
入门指南的目的是让您尽快启动并运行,以便您可以试验并测试Keycloak提供的各种授权功能。
此快速浏览很大程度上依赖于默认的数据库和服务器配置,并不包括复杂的部署选项。
有关功能或配置选项的详细信息,请参阅本文档中的相应部分。
指南介绍了有关Keycloak授权服务的主要概念:
主要为以下步骤:
您可以在配置为使用OpenID Connect协议的现有客户端应用程序中启用授权服务。您还可以创建新客户端。
创建客户端
为客户端应用程序启用授权服务时,Keycloak会自动为客户端授权配置创建多个默认设置。
更多信息,查看 启用授权服务 章节
前一章节已正确配置app-authz-vanilla资源服务器(或客户端)并启用了授权服务,则可以将其部署到服务器。
Keycloak Quickstarts Repository中提供了您要部署的应用程序的项目和代码。
您需要在计算机上安装以下内容并在PATH中使用,然后才能继续:
克隆项目
$ git clone https://github.com/keycloak/keycloak-quickstarts
本节构建和部署的项目位于:
$ cd keycloak-quickstarts/app-authz-jee-vanilla
在构建和部署应用程序之前,必须首先获取适配器配置。
要从Keycloak管理控制台获取适配器配置,请完成以下步骤:
"policy-enforcer": {
"on-deny-redirect-to" : "/app-authz-vanilla/error.jsp"
}
如果用户没有访问受保护资源的必要权限,而不是无用的403 Unauthorized消息,则此更改指定策略实施者将用户重定向到/app-authz-vanilla/error.jsp页面。
$ cd redhat-sso-quickstarts/app-authz-jee-vanilla
$ mvn clean package wildfly:deploy
应用部署成功, 访问: 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();
现在注销掉重新登录, 将无法访问应用
恢复默认的策略这个问题,不更改默认策略代码,而是使用策略代码文本区域下方的下拉列表将Logic更改为Negative。
这会重新启用对应用程序的访问,因为我们正在否定该策略的结果,该策略默认拒绝所有访问请求。
同样,在测试此更改之前,请务必注销并再次登录。
您还可以执行其他操作,例如:
除了在上一节中用作示例应用程序的app-authz-jee-vanilla快速入门之外,Keycloak Quickstarts Repository还包含其他使用本文档中描述的授权服务的应用程序。
每个quickstarts都有一个README文件,其中包含有关如何构建,部署和测试示例应用程序的说明。下表提供了可用授权快速入门的简要说明:
Name | Description |
---|---|
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的简单应用程序,演示如何启用对应用程序的用户管理访问,并允许用户管理其资源的权限。 |
根据OAuth2规范,资源服务器是托管受保护资源并能够接受和响应受保护资源请求的服务器。
在Keycloak中,资源服务器具有丰富的平台,用于对其受保护资源进行细粒度授权,其中可以基于不同的访问控制机制做出授权决策。
可以将任何客户端应用程序配置为支持细粒度权限。
这样做,您在概念上将客户端应用程序转换为资源服务器。
启用Keycloak授权服务的第一步是创建要转换为资源服务器的客户端应用程序。
http://${host}:${port}/my-resource-server
要将OIDC客户端应用程序转换为资源服务器并启用细粒度授权,请启用 Authorization Enabled 选项。
将为此客户端显示新的“Authorization”选项卡。单击“Authorization”选项卡,将显示类似于以下内容的页面:
“Authorization”选项卡包含其他子选项卡,其中包含实际保护应用程序资源必须遵循的不同步骤。
每个选项卡都由本文档中的特定主题单独介绍。
但这里有一个关于每一个的快速描述:
在“资源服务器设置”页面上,您可以配置策略强制模式,允许远程资源管理以及导出授权配置设置。
创建资源服务器时,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();
最后,默认权限称为默认权限,如果导航到“Permission”选项卡,则可以查看它。
此权限是基于资源的权限,用于定义一组应用于具有给定类型的所有资源的一个或多个策略。
您可以通过删除默认资源,策略或权限定义并创建自己的配置来更改默认配置。
使用URI创建默认资源,该URI使用/ *模式映射到应用程序中的任何资源或路径。
在创建自己的资源,权限和策略之前,请确保默认配置不会与您自己的设置冲突。
默认配置定义映射到应用程序中所有路径的资源。如果您要为自己的资源写入权限,请确保删除默认资源或将其URIS字段更改为应用程序中更具体的路径。否则,与默认资源关联的策略(默认情况下始终授予访问权限)将允许Keycloak授予对任何受保护资源的访问权限。
可以导出和下载资源服务器(或客户端)的配置设置。
您还可以导入资源服务器的现有配置文件。
当您要为资源服务器创建初始配置或更新现有配置时,导入和导出配置文件很有用。
配置文件包含以下定义:
配置文件以JSON格式导出并显示在文本区域中,您可以从中复制和粘贴。
您也可以单击“下载”下载配置文件并保存。
资源管理比较简单
创建资源服务器后,您可以开始创建要保护的资源和范围。
可以通过分别导航到Resource和Scope选项卡来管理资源和范围。
在“资源”页面上,您可以看到与资源服务器关联的资源列表。
资源列表提供有关受保护资源的信息:
在此列表中,您还可以通过单击要为其创建权限的资源的“Create Permission”来直接创建权限。
在为资源创建权限之前,请确保已经定义了要与权限关联的策略。
创建资源非常简单和通用。
您主要关心的是您创建的资源的粒度。
换句话说,可以创建资源来表示一组一个或多个资源,并且定义它们的方式对于管理权限至关重要。
在Keycloak中,资源定义了一组对不同类型资源通用的信息,例如:
资源可能具有与之关联的属性。这些属性可用于提供有关资源的其他信息,并在评估与资源关联的权限时为策略提供其他信息。
每个属性都是键和值对,其中值可以是一个或多个字符串的集合。
通过用逗号分隔每个值,可以为属性定义多个值。
资源的类型字段可用于将不同的资源组合在一起,因此可以使用一组通用权限来保护它们。
资源也有所有者。默认情况下,资源由资源服务器拥有。
但是,资源也可以与用户关联,因此您可以基于资源所有者创建权限。
例如,仅允许资源所有者删除或更新给定资源。
资源管理也通过Protection API公开,以允许资源服务器远程管理其资源。
使用Protection API时,可以实施资源服务器来管理其用户拥有的资源。在这种情况下,您可以指定用户标识符以将资源配置为属于特定用户。
Keycloak为资源服务器提供对其资源的完全控制。
将来,我们应该能够允许用户控制自己的资源以及批准授权请求和管理权限,尤其是在使用UMA协议时。
如上所述,策略定义在授予对象访问权限之前必须满足的条件。
通过在编辑资源服务器时单击“Policy”选项卡,可以查看与资源服务器关联的所有策略。
在此选项卡上,您可以查看以前创建的策略列表以及创建和编辑策略。
要创建新策略,请在策略列表的右上角,从“创建策略”下拉列表中选择策略类型。有关每种策略类型的详细信息,请参阅本节。
可以使用此类策略来定义允许一组一个或多个用户访问对象权限。
要创建新的基于用户的策略,请在策略列表右上角的下拉列表中选择User。
Add a User-Based Policy
您可以使用此类策略为允许一组一个或多个角色访问对象的权限定义条件。
默认情况下,没有指定添加到此策略的角色,如果该用户的任何一个角色被授予该权限,则策略将授予访问权限。
如果要强制执行特定角色,则可以根据需要指定特定角色。您还可以组合必需和非必需的角色,无论它们是领域角色还是客户角色。
当您需要更多受限制的基于角色的访问控制(RBAC)时,角色策略非常有用,其中必须强制执行特定角色以授予对对象的访问权限。
例如,您可以强制用户必须同意允许客户端应用程序(代表用户)访问用户的资源。
您可以使用Keycloak客户端作用域映射来启用同意页面,甚至强制客户端在从Keycloak服务器获取访问令牌时显式提供作用域。
要创建新的基于角色的策略,请在策略列表右上角的下拉列表中选择“Role”。
Add Role-Based Policy
创建基于角色的策略时,可以将特定角色指定为必需。执行此操作时,仅当请求访问权限的用户已被授予所有必需角色时,策略才会授予访问权限。可以像这样配置域和客户端角色。
定义必须的角色,需要勾选"Required"复选框
当您的策略定义多个角色但只有其中一部分是必需的时,必须的角色非常有用。
在这种情况下,您可以组合领域和客户端角色,以便为您的应用程序启用更细粒度的基于角色的访问控制(RBAC)模型。
例如,您可以拥有特定于客户端的策略,并且需要与该客户端关联的特定客户端角色。
或者,您可以强制仅在存在特定领域角色的情况下授予访问权限。
您还可以在同一策略中组合这两种方法。
您可以使用此类策略来使用JavaScript定义权限的条件。
它是Keycloak支持的基于规则的策略类型之一,并提供基于Evaluation API编写任何策略的灵活性。
要创建基于JavaScript的策略,请在策略列表右上角的下拉列表中选择JavaScript。
Add Javascript Policy
var context = $evaluation.getContext();
var contextAttributes = context.getAttributes();
if (contextAttributes.containsValue('kc.client.network.ip_address', '127.0.0.1')) {
$evaluation.grant();
}
以下是基于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();
}
这些属性是根据授权请求中使用的令牌中定义的任何声明进行映射的
var context = $evaluation.getContext();
var identity = context.getIdentity();
if (identity.hasRealmRole('keycloak_user')) {
$evaluation.grant();
}
或者,您可以检查用户是否被授予my-client-role客户端角色,其中my-client是客户端应用程序的客户端ID:
var context = $evaluation.getContext();
var identity = context.getIdentity();
if (identity.hasClientRole('my-client', 'my-client-role')) {
$evaluation.grant();
}
var realm = $evaluation.getRealm();
if (realm.isUserInRealmRole('marta', 'role-a')) {
$evaluation.grant();
}
或者检查客户端角色是否授予用户
var realm = $evaluation.getRealm();
if (realm.isUserInClientRole('marta', 'my-client', 'some-client-role')) {
$evaluation.grant();
}
检查领域角色是否授权给组
var realm = $evaluation.getRealm();
if (realm.isGroupInRole('/Group A/Group D', 'role-a')) {
$evaluation.grant();
}
将任意声明推送到资源服务器 要将任意声明推送到资源服务器,以便提供有关如何强制执行权限的其他信息:
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');
}
检查组成员身份
var realm = $evaluation.getRealm();
if (realm.isUserInGroup('marta', '/Group A/Group B')) {
$evaluation.grant();
}
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的对象。有关可从此界面访问的内容的更多信息,请参阅Evaluation API。
使用此类策略,您可以使用Drools(规则评估环境)定义权限的条件。它是Keycloak支持的基于规则的策略类型之一,并提供基于Evaluation API编写任何策略的灵活性。
要创建新的基于规则的策略,请在策略列表右上角的下拉列表中选择“Rule”
Add Rule Policy
以下是基于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
您可以使用另一个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
有关可以从org.keycloak.authorization.policy.evaluation.Evaluation界面访问的内容的更多信息,请参阅Evaluation API。
您可以使用此类策略来定义权限的时间条件。
要创建新的基于时间的策略,请在策略列表右上角的下拉列表中选择"Time"。
Add Time Policy
只有满足所有条件,才能授予访问权限。 Keycloak将根据每个条件的结果执行AND。
如前所述,Keycloak允许您构建策略策略,这一概念称为聚合策略。您可以使用策略聚合来重用现有策略来构建更复杂的策略,并使您的权限与处理授权请求期间评估的策略更加分离。
要创建新的聚合策略,请在策略列表右上角的下拉列表中选择“Aggregated”。
Add an Aggregated Policy
假设您有一个名为机密资源的资源,只能由来自keycloak.org域的用户和特定范围的IP地址访问。您可以使用这两个条件创建单个策略。但是,您希望重用此策略的域部分以应用于无论源网络如何都运行的权限。您可以为域和网络条件创建单独的策略,并根据这两个策略的组合创建第三个策略。使用聚合策略,您可以自由组合其他策略,然后将新聚合策略应用于您想要的任何权限。
创建聚合策略时,请注意不要在策略之间引入循环引用或依赖关系。如果检测到循环依赖关系,则无法创建或更新策略。
在创建聚合策略时,您还可以定义决策策略,该策略将用于根据每个策略的结果确定最终决策。
您可以使用此类策略来定义允许一组一个或多个客户端访问对象的权限条件。
要创建新的基于客户端的策略,请在策略列表右上角的下拉列表中选择“Client”
Add a Client-Based Policy
Add Group-Based Policy
默认情况下,向此策略添加组时,访问限制仅适用于所选组的成员。
在某些情况下,可能有必要不仅允许访问组本身,还允许访问层次结构中的任何子组。对于添加的任何组,您可以标记一个复选框Extend to Children以扩展对子组的访问。
Extending Access to Child Groups
在上面的示例中,该策略授予IT或其任何子级的任何用户成员的访问权限
可以使用正逻辑或负逻辑配置策略。
简而言之,您可以使用此选项来定义策略结果是保持原样还是被否定。
例如,假设您要创建一个策略,其中只应授予未授予特定角色的用户访问权限。
在这种情况下,您可以使用该角色创建基于角色的策略,并将其逻辑字段设置为Negative。
如果保持 Positive,这是默认行为,则策略结果将保持不变。
使用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(); }
处理授权请求时,Keycloak会在评估任何策略之前创建一个Evaluation实例。
然后将此实例传递给每个策略以确定访问是GRANT还是DENY。
策略通过在Evaluation实例上调用grant()或deny()方法来确定此方法。
默认情况下,Evaluation实例的状态为拒绝,这意味着您的策略必须显式调用grant()方法,以向策略评估引擎指示应该授予权限。
有关Evaluation
API的更多信息,请参阅JavaDocs。
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是基于与授权请求一起发送的OAuth2访问令牌构建的,并且此构造可以访问从原始令牌中提取的所有声明。例如,如果您使用Protocol Mapper 在OAuth2访问令牌中包含自定义声明,您还可以从策略访问此声明并使用它来构建条件。
EvaluationContext还允许您访问与执行和运行时环境相关的属性。目前,只有少数内置属性。
Name | Description | Type |
---|---|---|
kc.time.date_time | 当前日期时间 | String. Format MM/dd/yyyy hh:mm:ss |
kc.client.network.ip_address | IPv4 address of the client | String |
kc.client.network.host | 客户端主机名称 | String |
kc.client.id | The client id | String |
kc.client.user_agent | The value of the ‘User-Agent’ HTTP header | String[] |
kc.realm.name | The name of the realm | String |
权限将受保护的对象与必须评估的策略相关联,以决定是否应授予访问权限。
在创建要保护的资源以及要用于保护这些资源的策略之后,您可以开始管理权限。
要管理权限,请在编辑资源服务器时单击“Permissions”选项卡。
Permissions
可以创建权限以保护两种主要类型的对象:
要创建权限,请从权限列表右上角的下拉列表中选择要创建的权限类型。以下部分更详细地描述了这两种类型的对象。
要创建新的基于资源的权限,请在权限列表右上角的下拉列表中选择“Resource-based”。
Add Resource-Based Permission
资源权限还可用于定义要应用于具有给定类型的所有资源的策略。
当您拥有共享公共访问要求和约束的资源时,这种基于资源的权限形式非常有用。
通常,应用程序中的资源可以根据它们封装的数据或它们提供的功能进行分类(或类型)。例如,财务应用程序可以管理不同的银行账户,其中每个账户属于特定客户。虽然它们是不同的银行账户,但它们共享由银行组织全球定义的共同安全要求和约束。使用资源权限类型,您可以定义要应用于所有银行帐户的公共策略,例如:
要创建资源权限类型,请在创建新的基于资源的权限时单击“ Apply to Resource Type”。
通过将“Apply to Resource Type”设置为“On”,您可以指定要保护的类型以及要应用的策略,以管理对您指定类型的所有资源的访问。
基于范围的权限定义一组一个或多个范围,以使用一组一个或多个授权策略进行保护。与基于资源的权限不同,您可以使用此权限类型不仅为资源创建权限,还为与其关联的作用域创建权限,在定义管理资源的权限以及可对其执行的操作时提供更多粒度。
要创建新的基于范围的权限,请在权限列表右上角的下拉列表中选择“Scope-based”。
Add Scope-Based Perission
在设计策略时,您可以模拟授权请求以测试策略的评估方式。
可以通过单击“Evaluate”选项卡来访问策略评估工具。在那里,您可以指定不同的输入来模拟真实的授权请求并测试策略的效果。
身份信息过滤器可用于指定请求权限的用户
上下文信息过滤器可用于为评估上下文定义其他属性,以便策略可以获取这些相同的属性。
权限过滤器可用于构建授权请求。您可以为一组一个或多个资源和范围请求权限。如果要基于所有受保护资源和作用域模拟授权请求,请单击“添加”,而不指定任何“资源”或“作用域”。
输入所需信息后,单击“Evaluate”。
Keycloak授权服务建立在众所周知的标准之上,例如OAuth2和用户管理访问规范。
OAuth2客户端(例如前端应用程序)可以使用令牌端点从服务器获取访问令牌,并使用这些相同的令牌来访问受资源服务器保护的资源(例如后端服务)。同样,Keycloak授权服务提供对OAuth2的扩展,以允许基于与所请求的资源或范围相关联的所有策略的处理来发布访问令牌。这意味着资源服务器可以根据服务器授予的权限强制访问其受保护资源,并由访问令牌持有。在Keycloak授权服务中,具有权限的访问令牌称为请求方令牌或简称RPT。
除了发布RPT之外,Keycloak授权服务还提供了一组RESTful端点,允许资源服务器管理其受保护的资源,范围,权限和策略,帮助开发人员将这些功能扩展或集成到他们的应用程序中,以支持细粒度的授权
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
{ "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" }
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中提供操作创建,读取,更新和删除权限票证。
要从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支持两种令牌格式:
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响应时,此参数特别有用。
可能的值是:
{
'result': true
}
[
{
'rsid': 'My Resource'
'scopes': ['view', 'update']
},
...
]
授权请求示例 - 客户端访问受保护的两个资源
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"
客户端正在寻求访问受资源服务器保护的任何资源和范围时的授权请求示例。
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受保护资源时的授权请求示例:
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响应客户端
HTTP/1.1 200 OK
Content-Type: application/json
...
{
"access_token": "${rpt}",
}
服务器的响应与使用其他授权类型时来自令牌端点的任何其他响应一样。可以从access_token响应参数获得RPT。如果客户端未获得授权,Keycloak将使用403 HTTP状态代码进行响应:
keycloak 拒绝授权请求
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
grant 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"
当客户端代表用户行事时,此方法特别有用。
在这种情况下,承载令牌是先前由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"
从服务器获取权限时,您可以推送任意声明,以便在评估权限时将这些声明提供给您的策略。
如果要在不使用权限票证(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}"
claim_token参数需要BASE64编码的JSON,其格式类似于以下示例:
{
"organization" : ["acme"]
}
格式需要一个或多个声明,其中每个声明的值必须是字符串数组。
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授予其他权限。
在UMA中,授权过程在客户端尝试访问受UMA保护的资源服务器时启动。
受UMA保护的资源服务器期望令牌中的承载令牌,其中令牌是RPT。当客户端在没有权限票证的情况下在资源服务器上请求资源时:
客户端在不发送RPT的情况下请求受保护资源
curl -X GET \
http://${host}:8080/my-resource-server/resource/1bfdfe78-a4e1-4c2d-b142-fc92b75b986f
资源服务器使用权限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"
权限票证是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}
如果$ Keycloak评估过程导致发布权限,它会发出与其关联权限的RPT:
Keycloak使用RPT响应客户端
HTTP/1.1 200 OK
Content-Type: application/json
...
{
"access_token": "${rpt}",
}
服务器的响应与使用其他授权类型时来自令牌端点的任何其他响应一样。可以从access_token响应参数获得RPT。如果客户端未被授权拥有权限,Keycloak将使用403 HTTP状态代码进行响应:
Keycloak拒绝授权请求
HTTP/1.1 403 Forbidden
Content-Type: application/json
...
{
"error": "access_denied",
"error_description": "request_denied"
}
作为授权过程的一部分,客户端首先需要从受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"
}
此类响应表示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"
使用submit_request参数时,Keycloak将为拒绝访问的每个资源保留一个权限请求。创建后,资源所有者可以检查其帐户并管理其权限请求。
您可以将此功能视为应用程序中的“请求访问”按钮,用户可以在其中要求其他用户访问其资源。
用户可以使用Keycloak用户帐户服务管理对其资源的访问。要启用此功能,必须首先为您的领域启用用户管理的访问权限。为此,请在Keycloak管理控制台中打开领域设置页面并启 User-Managed Access switch。
在左侧菜单中,“我的资源”选项指向用户可以执行以下操作的页面:
管理需要我批准的权限请求(Need My approval)
此部分包含等待批准的所有权限请求的列表。这些请求连接到请求访问特定资源的各方(用户)。允许用户批准或拒绝这些请求。
管理我的资源(My resources)
此部分包含用户拥有的所有资源的列表。用户可以单击资源以获取更多详细信息,并与其他人共享资源。
管理共享给我的资源
此部分包含与用户共享的所有资源的列表。
管理正在等待批准的权限申请
此部分包含用户发送的等待另一个用户或资源所有者批准的权限请求列表。
当用户通过单击“My resources”列表中的任何资源选择详细显示其资源时,他将重定向到页面,如下所示:
管理有权访问资源的人员
此部分包含有权访问资源的人员列表。允许用户通过单击“撤消”按钮或删除特定权限来撤消访问权限。
共享资源给其他人
通过键入其他用户的用户名或电子邮件,用户可以共享资源并选择他要授予访问权限。
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的令牌。
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"
上面的示例使用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"
}
Keycloak可以通过不同方式验证您的客户端应用程序。为简单起见,此处使用client_credentials grant类型,这需要client_id和client_secret。您可以选择使用任何支持的身份验证方法。
资源服务器可以使用符合UMA的端点远程管理其资源:
http://${host}:${port}/auth/realms/${realm_name}/authz/protection/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"
]
}'
默认情况下,资源的所有者是资源服务器。如果要定义其他所有者(例如特定用户),可以按如下方式发送请求:
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属性,如下所示:
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
}'
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"
]
}'
curl -v -X DELETE \
http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set/{resource_id} \
-H 'Authorization: Bearer '$pat
http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set/{resource_id}
根据名称查询
http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set?name=Alice Resource
根据uri查询
http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set?uri=/api/alice
根据所有者查询
http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set?owner=alice
根据类型查询
http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set?type=albums
根据范围查询
http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set?scope=read
在查询服务器的权限时,请使用参数first和max results来限制结果
使用UMA协议的资源服务器可以使用特定端点来管理权限请求。此端点提供符合UMA的流,用于注册权限请求和获取权限票证。
http://${host}:${port}/auth/realms/${realm_name}/authz/protection/permission
Permission Ticket是表示权限请求的特殊安全令牌类型。根据UMA规范,许可权证是:
从授权服务器传递到资源服务器,从资源服务器传递到客户端,最终从客户端传送回授权服务器的关联句柄,以使授权服务器能够评估应用于请求的正确策略
授权数据。
在大多数情况下,您不需要直接处理此端点。Keycloak提供了一个策略实施器,为您的资源服务器启用UMA,以便它可以从授权服务器获取权限票证,将此票证返回到客户端应用程序,并根据最终请求方令牌(RPT)强制执行授权决策。
从Keycloak获取许可票证的过程由资源服务器而不是常规客户端应用程序执行,其中当客户端尝试访问受保护资源而没有访问资源的必要授权时获取许可票证。使用UMA时发布权限票证是一个重要方面,因为它允许资源服务器:
许可证也有值得强调的重要方面:
这些只是UMA带来的一些好处,其中UMA的其他方面强烈基于许可票证,特别是关于隐私和用户控制的资源访问。
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"
]
}
]'
创建票证时,您还可以推送任意声明并将这些声明与票证相关联:
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"]
}
}
]'
在评估与许可权证相关联的资源和范围的权限时,您的策略可以使用这些声明。
Keycloak利用UMA Protection API允许资源服务器管理其用户的权限。
除了资源和权限API之外,Keycloak还提供了一个Policy API,资源服务器可以代表其用户将权限设置为资源。
Policy API可在以下位置获得:
http://${host}:${port}/auth/realms/${realm_name}/authz/protection/uma-policy/{resource_id}
此API受承载令牌保护,该承载令牌必须表示用户授予资源服务器以代表其管理权限的同意。承载令牌可以是从令牌端点获得的常规访问令牌,使用:
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范围。
您还可以使用其他访问控制机制创建策略,例如使用组:
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"]
}'
或者特定的用户:
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自定义策略
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请求,如下所示:
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 GET请求,如下所示:
http://${host}:${post}/auth/realms/${realm}/authz/protection/uma-policy?name=Any people manager
要查询与特定范围关联的权限,请发送HTTP GET请求,如下所示:
http://${host}:${post}/auth/realms/${realm}/authz/protection/uma-policy?scope=read
要查询所有权限,请发送HTTP GET请求,如下所示:
http://${host}:${post}/auth/realms/${realm}/authz/protection/uma-policy
在查询服务器的权限时,请使用参数first和max results来限制结果。
请求方令牌(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" }
通过此令牌,您可以从权限声明中获取服务器授予的所有权限。
另请注意,权限与您要保护的资源/作用域直接相关,并且与用于实际授予和颁发这些相同权限的访问控制方法完全分离。
令牌内省本质上是一个OAuth2令牌内省兼容端点,您可以从中获取有关RPT的信息。
http://${host}:${port}/auth/realms/${realm_name}/protocol/openid-connect/token/introspect
要使用此端点对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"
上面的请求使用HTTP BASIC并传递客户端的凭据(客户端ID和密码)来验证尝试内省令牌的客户端,但您可以使用Keycloak支持的任何其他客户端身份验证方法。
内省端点需要两个参数:
因此,服务器响应是:
{
"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未激活,则返回此响应:
{
"active": false
}
不会。就像Keycloak服务器发布的常规访问令牌一样,RPT也使用JSON Web令牌(JWT)规范作为默认格式。
这基本上是策略执行者所做的。
务必:
根据您的要求,资源服务器应该能够远程管理资源,甚至可以以编程方式检查权限。如果您使用的是Java,则可以使用Authorization Client API访问Keycloak授权服务。
它的目标是希望访问服务器提供的不同端点的资源服务器,例如令牌端点,资源和权限管理端点。
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-client</artifactId>
<version>${KEYCLOAK_VERSION}</version>
</dependency>
</dependencies>
keycloak.json
{
"realm": "hello-world-authz",
"auth-server-url" : "http://localhost:8080/auth",
"resource" : "hello-world-authz-service",
"credentials": {
"secret": "secret"
}
}
realm(必需): 领域名称
auth-server-url(必需):
Keycloak服务器的基本URL。所有其他Keycloak页面和REST服务端点都源于此。它通常采用https://host:port/auth格式。
resource(必需):
应用程序的客户端ID。每个应用程序都有一个client-id,用于标识应用程序。
credentials(必需):
指定应用程序的凭据。这是一个对象表示法,其中键是凭证类型,值是凭证类型的值。
考虑到类路径中有keycloak.json文件,可以创建一个新的AuthzClient实例,如下所示:
// create a new instance based on the configuration defined in a keycloak.json located in your classpath
AuthzClient authzClient = AuthzClient.create();
以下是说明如何获取用户权利的示例:
// create a new instance based on the configuration defined in keycloak-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
以下示例说明如何获取一组一个或多个资源的用户权利:
/ 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
// 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);
// 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); }
策略执行点(PEP)是一种设计模式,因此您可以以不同的方式实现它。
Keycloak提供了为不同平台,环境和编程语言实现PEP的所有必要手段。
Keycloak授权服务提供RESTful API,并利用OAuth2授权功能使用集中授权服务器进行细粒度授权。
PEP负责执行Keycloak服务器的访问决策,通过评估与受保护资源相关的策略来做出这些决策。它充当应用程序中的过滤器或拦截器,以检查是否可以根据这些决策授予的权限来满足对受保护资源的特定请求。
根据您使用的协议强制执行权限。使用UMA时,策略实施者始终期望将RPT作为承载令牌,以便决定是否可以提供请求。这意味着客户端应首先从Keycloak获取RPT,然后再向资源服务器发送请求。
但是,如果您不使用UMA,还可以将常规访问令牌发送到资源服务器。在这种情况下,策略实施器将尝试直接从服务器获取权限。
如果您使用任何Keycloak OIDC适配器,则可以通过将以下属性添加到keycloak.json文件来轻松启用策略实施器:
keycloak.json
{
"policy-enforcer": {}
}
当您启用策略实施器时,所有发送应用程序的请求都会被截获,并且将根据Keycloak授予发出请求的标识的权限授予对受保护资源的访问权限。
策略实施与您的应用程序的路径以及使用Keycloak管理控制台为资源服务器创建的资源密切相关。默认情况下,在创建资源服务器时,Keycloak会为资源服务器创建默认配置,以便您可以快速启用策略实施。
要为应用程序启用策略实施,请将以下属性添加到keycloak.json文件中:
keycloak.json
{
"policy-enforcer": {}
}
如果您想手动定义受保护的资源,或者更详细一点:
{ "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/*" } ] } }
以下是每个配置选项的说明:
policy-enforcer
指定用于定义策略实际实施方式的配置选项,以及可选择要保护的路径。如果未指定,策略实施器将向服务器查询与受保护资源服务器关联的所有资源。在这种情况下,您需要确保使用与要保护的路径匹配的URIS属性正确配置资源。
user-managed-access
指定适配器使用UMA协议。如果指定,则适配器向服务器查询权限票证,并根据UMA规范将它们返回给客户端。如果未指定,策略实施器将能够基于常规访问令牌或RPT强制执行权限。在这种情况下,在令牌缺少权限时拒绝访问资源之前,策略实施器将尝试直接从服务器获取权限。
enforcement-mode
指定策略的实施方式。
on-deny-redirect-to
定义从服务器获取“access denied”消息时重定向客户端请求的URL。默认情况下,适配器使用403 HTTP状态代码进行响应。
path-cache
定义策略实施者应如何跟踪应用程序中的路径与Keycloak中定义的资源之间的关联。需要缓存以通过缓存路径和受保护资源之间的关联来避免对Keycloak服务器的不必要请求。
paths
指定要保护的路径。此配置是可选的。如果未定义,策略实施器将通过在Keycloak中获取您为应用程序定义的资源来发现所有路径,其中这些资源是使用表示应用程序中某些路径的URIS定义的。
name
服务器上与给定路径关联的资源的名称。当与路径一起使用时,策略实施器会忽略资源的URIS属性并使用您提供的路径。
path
(必需) 相对于应用程序上下文路径的URI。如果指定了此选项,则策略实施器将在服务器中查询具有相同值的URI的资源。目前支持路径匹配的非常基本的逻辑。有效路径的示例如下:
methods
要保护的HTTP方法(例如,GET,POST,PATCH)以及它们如何与服务器中给定资源的范围相关联。
enforcement-mode
指定策略的实施方式。
claim-information-point
定义一组必须解析并推送到Keycloak服务器的一个或多个声明,以使这些声明可用于策略。有关详细信息,请参阅Claim Information Point。
lazy-load-paths
指定适配器如何获取服务器以获取与应用程序中的路径关联的资源。如果为true,则策略实施器将根据请求的路径相应地按需获取资源。如果您不希望在部署期间从服务器获取所有资源(如果您没有提供路径),或者您只定义了一组子路径并希望按需获取其他资源,则此配置特别有用。
声明信息点(CIP)负责解决声明并将这些声明推送到Keycloak服务器,以便提供有关策略访问上下文的更多信息。
可以将它们定义为策略实施者的配置选项,以便解决来自不同来源的声明,例如:
在向Keycloak服务器推送声明时,策略不仅可以基于用户是谁,还可以根据给定事务的人员,内容,原因,时间,地点和内容来考虑上下文和内容。它完全是关于基于上下文的授权以及如何使用运行时信息来支持细粒度的授权决策。
以下是几个示例,说明如何从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']} " } } } ] }
以下是几个示例,说明如何从外部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']}" } } } } ] }
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"],
}
}
}
]
}
开发人员可以使用声明信息提供程序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); } }
每个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; } }
启用策略实施(enforcement)后,可以通过org.keycloak.AuthorizationContext获取从服务器获取的权限。此类提供了几种可用于获取权限的方法,并确定是否为特定资源或范围授予了权限。
获取Servlet容器中的授权上下文:
HttpServletRequest request = ... // obtain javax.servlet.http.HttpServletRequest
KeycloakSecurityContext keycloakSecurityContext =
(KeycloakSecurityContext) request.getAttribute(KeycloakSecurityContext.class.getName());
AuthorizationContext authzContext =
keycloakSecurityContext.getAuthorizationContext();
有关如何获取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
}
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
}
尽管两个示例都满足相同的要求,但它们以不同的方式实现。在RBAC中,角色仅隐式定义其资源的访问权限。使用Keycloak,您可以创建更易于管理的代码,无论您使用的是RBAC,基于属性的访问控制(ABAC)还是任何其他BAC变体,都可以直接关注您的资源。您是否拥有给定资源或范围的权限,或者您没有。
现在,假设您的安全要求已更改,除项目经理外,PMO还可以创建新项目。
安全要求会发生变化,但使用Keycloak时,无需更改应用程序代码即可满足新要求。一旦您的应用程序基于资源和范围标识符,您只需更改与授权服务器中的特定资源关联的权限或策略的配置。在这种情况下,将更改与项目资源和/或作用域urn:project.com:project:create关联的权限和策略。
AuthorizationContext还可用于获取对应用程序配置的Authorization Client API的引用
ClientAuthorizationContext clientContext = ClientAuthorizationContext.class.cast(authzContext);
AuthzClient authzClient = clientContext.getClient();
在某些情况下,受策略实施者保护的资源服务器需要访问授权服务器提供的API。有了AuthzClient实例,资源服务器可以与服务器交互,以便以编程方式创建资源或检查特定权限。
Keycloak Server附带了一个JavaScript库,您可以使用该库与受策略实施者保护的资源服务器进行交互。此库基于Keycloak JavaScript适配器,可以集成该适配器以允许客户端从Keycloak Server获取权限。
您可以通过在网页中包含以下脚本标记从运行Keycloak Server实例获取此库:
<script src="http://.../auth/js/keycloak-authz.js"></script>
完成后,您可以创建KeycloakAuthorization实例,如下所示:
var keycloak = ... // obtain a Keycloak instance from keycloak.js library
var authorization = new KeycloakAuthorization(keycloak);
keycloak-authz.js库提供了两个主要功能:
在这两种情况下,库都允许您轻松地与资源服务器和Keycloak授权服务进行交互,以获取具有客户端可用作承载令牌的权限的令牌,以访问资源服务器上的受保护资源。
如果资源服务器受策略实施器保护,它将根据随承载令牌携带的权限来响应客户端请求。
通常,当您尝试使用缺少访问受保护资源的权限的承载令牌访问资源服务器时,资源服务器将使用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"
有关更多信息,请参阅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
});
authorize函数是完全异步的,并支持一些回调函数来接收来自服务器的通知:
大多数应用程序应使用onGrant回调在401响应后重试请求。后续请求应包括RPT作为重试的承载令牌。
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
});
有关如何获取具有特定资源和范围权限的RPT的示例
authorization.entitlement('my-resource-server', {
"permissions": [
{
"id" : "Some Resource"
}
]
}).then(function (rpt) {
// onGrant
});
使用授权功能时,必须提供要访问的资源服务器的client_id。
授权功能是完全异步的,并支持一些回调函数来接收来自服务器的通知:
authorize
和entitlement
函数都接受授权请求对象。可以使用以下属性设置此对象:
permissions
表示资源和范围的对象数组。例如
var authorizationRequest = {
"permissions": [
{
"id" : "Some Resource",
"scopes" : ["view", "edit"]
}
]
}
metadata
一个对象,其属性定义服务器应如何处理授权请求。
submit_request
一个布尔值,指示服务器是否应对权限票据引用的资源和作用域创建权限请求。此参数仅在与ticket参数一起用作UMA授权过程的一部分时生效。
如果您已使用库提供的任何授权函数获取了RPT,则始终可以从授权对象获取RPT,如下所示(假设它已通过前面介绍的技术之一进行了初始化):
var rpt = authorization.rpt;
当服务器使用HTTPS时,请确保您的适配器配置如下:
{
"truststore": "path_to_your_trust_store",
"truststore-password": "trust_store_password"
}
上面的配置为授权客户端启用TLS / HTTPS,从而可以使用HTTPS方案远程访问Keycloak服务器。
强烈建议您在访问Keycloak Server端点时启用TLS / HTTPS。
https://www.keycloak.org/docs/latest/authorization_services/index.html#_enforcer_claim_information_point
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。