密钥斗篷中的资源、范围、权限和策略

我想用“钥匙斗篷”的授权系统创建一个相当简单的以角色为基础的存取控制系统。正在替换的系统“钥匙斗篷”允许我们创建一个“用户”,该用户是一个或多个“组”的成员。在这个遗留系统中,用户被赋予“权限”,可以通过组成员关系(其中分配了组的权限)或直接向用户授予权限来访问大约250个“功能”中的每一个。

我想将遗留系统映射到密钥斗篷授权。

对于我来说,将现有系统中的每个“功能”映射到一个密钥斗篷资源和一组密钥斗篷作用域应该很简单。例如,“ viewAccount”功能显然会映射到一个“ account”资源和一个“ view”作用域; 而“ viewTransaction”则映射到一个“ action”资源... ... 但是,只创建一个“ view”作用域并跨多个资源(帐户、事务等)使用它是否是最佳实践呢?或者我应该创建一个“ viewAccount”作用域,一个“ viewTransaction”作用域,等等?

同样,我对权限也有点困惑。对于资源和范围的每个实际组合,通常的做法是创建权限吗?如果有多个权限匹配给定的资源/作用域,那么钥匙斗篷会做什么?我猜想 Keycloak 的意图是允许我配置一个对资源和范围的权限矩阵,例如,我可以有权访问“帐户”和“查看”范围的权限,因此我将有权查看帐户?

我问这个问题是因为所有这一切的结果似乎是我的旧的“ viewAccount”功能最终创建了一个“ Account”资源,具有“ View”作用域和一个“ viewAccount”权限,这似乎让我回到了原来的位置。如果正确的话,也没关系。

最后,显然我需要一组策略来确定是否应该应用 viewAccount。但是,这是否意味着我需要针对用户可能属于的每个遗留组的策略?例如,如果我有一个“ help desk”角色,那么我需要一个“ help desk member”策略,然后我可以将它添加到“ viewAccount”权限中。是这样吗?

谢谢,

马克

88503 次浏览

我知道我迟到了两年多,但我认为我应该分享我所知道的,希望能减轻未来读者的痛苦。完全透明——我绝不是一个 Keycloak/OAuth/OIDC 专家,我所知道的大部分是通过阅读文档、书籍、好的 ol’YouTube 和使用这个工具。

该员额将由两部分组成:

  1. 我会尽力回答你们所有的问题
  2. 我将向大家展示如何在 Keycloak 使用策略/范围/权限,而无需部署单独的应用程序,以便更好地理解这个线程中的一些核心概念。请注意,虽然这主要是为了让你所有的开始。我用的是 Keycloak 8.0.0

第一部分

在我们开始之前,有一些术语:

  • 在 Keycloak,您可以创建两种类型的权限: 资源为本基于范围
  • 简单地说,对于 Resource-Based权限,您可以将它直接应用到您的资源
  • 对于 Scoped-Based权限,应将其应用于范围或范围 还有资源。

只创建一个“视图”作用域并跨多个资源(帐户、事务等)使用它是否是最佳实践?或者我应该创建一个“ viewAccount”作用域,一个“ viewTransaction”作用域,等等?

作用域表示受保护资源上的一组权限。在您的例子中,您有两个资源: accounttransaction,因此我倾向于第二种方法。

从长远来看,拥有与所有资源(例如 accounttransactioncustomersettlement...)相关联的全局 view作用域使得授权难以管理和适应安全需求变化。

这里有一些例子,你可以通过检查来获得一种设计的感觉

但是请注意-我并不是说您不应该跨资源共享作用域。事实上,对于具有相同 type的资源,Keycloak允许这样做。例如,您可能需要同时使用 viewAccountviewTransaction作用域来读取给定帐户下的事务(毕竟您可能需要访问该帐户来查看事务)。您的需求和标准将严重影响您的设计。

对于资源和范围的每个实际组合,通常的做法是创建权限吗?

抱歉,我不是很明白这个问题,所以我就长话短说了。为了授予/拒绝访问 resource,您需要:

为了使政策执行生效,请参阅 授权程序

如何安排这一切完全取决于你自己,例如:

  • 定义单个策略,并将每个策略绑定到适当的许可下。

  • 更好的做法是,定义单个策略,然后将所有相关策略分组到一个 aggregated策略(一个策略的策略)下,然后将该聚合策略与 scope-based权限关联起来。您可以将该 scoped-based权限应用于资源及其所有相关作用域。

  • 或者,您可以通过利用这两种不同的类型进一步拆分您的权限。您可以通过 resource-based权限类型单独为资源创建权限,并通过 scope-based权限类型单独将其他权限与范围关联。

你有选择。

如果有多个权限匹配给定的资源/作用域,那么钥匙斗篷会做什么?

这取决于

  1. 资源服务器的 Decision Strategy
  2. 每个许可都是 Decision Strategy
  3. 每个保单的 Logic值。

Logic值类似于 Java 的 !运算符。它可以是 PositiveNegative。当 LogicPositive时,策略的最终评估保持不变。当它的 Negative时,最终的结果是否定的(例如,如果一个策略的计算结果为 false,而它的 LogicNegative,那么它将是 true)。为了简单起见,让我们假设 Logic总是设置为 Positive

Decision Strategy是我们真正想要解决的问题。 Decision Strategy可以是 Unanimous也可以是 Affirmative,

决策策略

此配置更改策略计算引擎如何根据所有计算权限的结果决定是否应授予资源或范围。是的意味着,为了授予对资源及其作用域的访问权限,必须至少有一个权限评估为肯定的决策。全票通过意味着所有权限必须评估为一个积极的决策,以便最终的决策也是积极的。例如,如果同一资源或作用域的两个权限发生冲突(其中一个授予访问权限,另一个拒绝访问权限) ,则如果选择的策略是肯定的,则将授予对该资源或作用域的权限。否则,对任何权限的单次拒绝也将拒绝对资源或范围的访问。

让我们用一个例子来更好地理解上面的内容。假设您有一个具有2个权限的资源,并且有人试图访问该资源(请记住,所有策略的 Logic都是 Positive)。现在:

  1. Permission OneDecision Strategy设置为 Affirmative。它还有3个策略,每个策略的评估结果如下:
    • true
    • false
    • false

因为其中一个策略被设置为 true,所以 Permission One被设置为 true(确认-只有1需要是 true)。

  1. Permission TwoDecision Strategy设置为 Unanimous,有两个策略:
    • true
    • false

在这种情况下,Permission Twofalse,因为有一个策略是假的(一致同意-它们都需要是 true)。

  1. 现在进行 期末考试评估。如果资源服务器的 Decision Strategy设置为 Affirmative,则将授予对该资源的访问权,因为 Permission Onetrue。另一方面,如果资源服务器的 Decision Strategy设置为 Unanimous,访问将被拒绝。

参见:

我们将继续讨论这个问题,在第二部分中我将解释如何设置资源服务器的 Decision Strategy

因此,例如,我可以有权访问“帐户”和“查看”范围的权限,因此我将有权查看帐户?

简短的回答是肯定的。现在,让我们再详细说明一下:)

如果你有以下情况:

  1. 资源服务器的 Decision Strategy设置为 UnanimousAffirmative
  2. 访问 account/{id}资源的权限为 true
  3. 访问 view范围的权限是 true

您将被授予查看帐户的权限。

  • true + true等于 AffirmativeUnanimous下的 true

如果你有这个

  1. 资源服务器的 Decision Strategy设置为 Affirmative
  2. 访问 account/{id}资源的权限为 true
  3. 访问 view范围的权限是 false

您将被授予 还有查看帐户的权限。

  • true + falseAffirmative策略下的 true

这里的要点是,对给定资源的访问也取决于您的设置,所以要小心,因为您可能不想要第二种情况。

但是,这是否意味着我需要针对用户可能属于的每个遗留组的策略?

我不太清楚两年前 Key枕表现如何,但是您可以指定一个 以团体为基础的政策,并在该策略下简单地添加所有组。您当然不需要为每个组创建一个策略。

例如,如果我有一个“ help desk”角色,那么我需要一个“ help desk member”策略,然后我可以将它添加到“ viewAccount”权限中。是这样吗?

差不多。有很多方法可以设置这个。例如,你可以:

  1. 创建您的资源(例如 /account/{id})并将其与 account:view作用域关联。
  2. 创建一个 基于角色的策略并在该策略下添加 helpdesk角色
  3. 创建一个名为 viewAccountScope-Based权限,并将其与 scoperesourcepolicy绑定

我们将在第 II 部分中设置类似的内容。

第二部分

钥匙斗篷有一个简洁的小工具,允许您测试您的所有策略。更好的是,您实际上不需要启动另一个应用程序服务器并部署一个单独的应用程序来实现这一点。

下面是我们设定的场景:

  1. 我们将创建一个名为 stackoverflow-demo的新域
  2. 我们将在该领域下创建一个 bank-api客户机
  3. 我们将为该客户机定义一个名为 /account/{id}的资源
  4. account/{id}将具有 account:view作用域
  5. 我们将在新领域下创建一个名为 bob的用户
  6. 我们还将创建三个角色: bank_telleraccount_owneruser
    • 我们不会将 bob与任何角色关联起来。现在不需要这样做。
  7. 我们将建立以下两个 Role-Based政策:
    • bank_telleraccount_owner可以访问 /account/{id}资源
    • account_owner可以访问 account:view范围
    • user不能访问资源或范围
  8. 我们将使用 Evaluate工具来了解如何授予访问权限 拒绝。

请原谅我,这个例子是不现实的,但我不熟悉银行业:)

钥匙斗篷设置

下载并运行“钥匙斗篷”

cd tmp
wget https://downloads.jboss.org/keycloak/8.0.0/keycloak-8.0.0.zip
unzip keycloak-8.0.0.zip
cd keycloak-8.0.0/bin
./standalone.sh

创建初始管理用户

  1. 转到 http://localhost:8080/auth
  2. 点击 Administration Console链接
  3. 创建管理用户和登录

请访问 开始了解更多信息。对于我们来说,以上就足够了。

准备舞台

创建一个新的领域

  1. 将鼠标悬停在 master领域并单击 Add Realm按钮。
  2. 输入 stackoverflow-demo作为名称。
  3. 点击 Create
  4. 左上角现在应该说 stackoverflow-demo而不是 master领域。

参见 创造一个新的领域

创建一个新用户

  1. 单击左侧的 Users链接
  2. 点击 Add User按钮
  3. 输入 username(例如 bob)
  4. 确保打开 User Enabled
  5. Save

参见 创建新用户

创建新角色

  1. 点击 Roles链接
  2. 点击 Add Role
  3. 添加以下角色: bank_telleraccount_owneruser

同样,将用户与角色关联起来。对于我们的目的,这是不需要的。

参见 角色

创建一个客户端

  1. 点击 Clients链接
  2. 点击 Create
  3. 输入 bank-api作为 Client ID
  4. 对于 Root URL,输入 http://127.0.0.1:8080/bank-api
  5. 点击 Save
  6. 确保 Client Protocolopenid-connect
  7. Access Type改为 confidential
  8. Authorization Enabled改为 On
  9. 向下滚动并点击 Save。一个新的 Authorization标签应该出现在顶部。
  10. 单击 Authorization选项卡,然后单击 Settings
  11. 确保将 Decision Strategy设置为 Unanimous
    • 这是资源服务器的 Decision Strategy

参见:

创建自定义作用域

  1. 单击 Authorization选项卡
  2. 点击 Authorization Scopes > Create打开 Add Scope页面
  3. 在名称中输入 account:view,然后按回车键。

创建“查看帐户资源”

  1. 点击上面的 Authorization链接
  2. 点击 Resources
  3. 点击 Create
  4. NameDisplay name输入 View Account Resource
  5. 输入 account/{id}作为 URI
  6. Scopes文本框中输入 account:view
  7. Save

参见 创建资源

制定你的政策

  1. 再次在 Authorization选项卡下,单击 Policies
  2. Create Policy下拉菜单中选择 Role
  3. Name部分中,键入 Only Bank Teller and Account Owner Policy
  4. Realm Roles下选择 bank_telleraccount_owner角色
  5. 确保将 Logic设置为 Positive
  6. Save
  7. 点击 Policies链接
  8. Create Policy下拉列表中再次选择 Role
  9. 这次对于 Name使用 Only Account Owner Policy
  10. Realm Roles下选择 account_owner
  11. 确保将 Logic设置为 Positive
  12. Save
  13. 单击顶部的 Policies链接,现在应该可以看到新创建的策略。

参见 基于角色的策略

一定要注意到钥匙斗篷有更强大的策略。参见 管理政策

创建基于资源的权限

  1. 再次在 Authorization选项卡下,单击 Permissions
  2. 选择 Resource-Based
  3. Name键入 View Account Resource Permission
  4. Resources类型 View Account Resource Permission
  5. Apply Policy下选择 Only Bank Teller and Account Owner Policy
  6. 确保将 Decision Strategy设置为 Unanimous
  7. Save

参见 创建基于资源的权限

呼..

基于资源的权限评估

  1. 再次在 Authorization选项卡下,选择 Evaluate
  2. User下输入 bob
  3. Roles下选择 user
    • 这是我们将用户与我们创建的角色相关联的地方。
  4. Resources下选择 View Account Resource并单击 Add
  5. 点击评估。
  6. 展开 View Account Resource with scopes [account:view]查看结果,您应该会看到 DENY

enter image description here

  1. 这是有意义的,因为我们只允许两个角色通过 Only Bank Teller and Account Owner Policy访问该资源。让我们测试一下,确保这是真的!
  2. 点击评估结果右上方的 Back链接
  3. 将 bob 的角色改为 account_owner并单击 Evaluate。您现在应该看到的结果是 PERMIT。如果你回去把角色改成 bank_teller也是一样

参见 评估和测试政策

创建基于范围的权限

  1. 回到 Permissions部分
  2. 这次在 Create Permission下拉列表中选择 Scope-Based
  3. Name下,输入 View Account Scope Permission
  4. Scopes下,输入 account:view
  5. Apply Policy下,输入 Only Account Owner Policy
  6. 确保将 Decision Strategy设置为 Unanimous
  7. Save

参见 创建基于范围的权限

第二次测试

评估我们的新变化

  1. 回到 Authorization部分
  2. 点击 Evaluate
  3. 用户应该是 bob
  4. 角色应该是 bank_teller
  5. 资源应该是 View Account Resource并单击 Add
  6. 点击 Evaluate,我们应该得到 DENY
    • 同样,这也不足为奇,因为 bank_teller可以访问 resource,但不能访问 scope。这里一个权限计算为 true,另一个计算为 false。假设资源服务器的 Decision Strategy被设置为 Unanimous,那么最终的决定是 DENY
  7. 单击 Authorization选项卡下的 Settings,将 Decision Strategy改为 Affirmative,然后返回到步骤1-6。这一次,最终结果应该是 PERMIT(一个权限为 true,因此最终决策为 true)。
  8. 为了完整起见,将资源服务器的 Decision Strategy返回到 Unanimous。再次回到步骤1到步骤6,但是这一次,将角色设置为 account_owner。这一次,最终的结果也是 PERMIT,这是有意义的,因为 account_owner可以访问 resourcescope

希望这个有帮助。

我希望通过纯 HTTP 方法实施授权,而不使用适配器,因为 Lua 没有适配器。希望这个答案可以帮助人们寻找基于非适配器的方法。

如果你正在寻找适配器的 快速启动指南快速启动指南是最好的地方开始。特别是 弹簧引导 authz 示例

对于纯 HTTP 实现:

第一步:

钥匙斗篷管理用户界面中定义策略和权限

第二步

有一个关于哪个 HTTP 路径属于哪个资源以及每个路径所需作用域的内部映射。这也可以保存在 配置文件中。当调用特定的路由时,调用 Key枕令牌端点来验证访问令牌的声明。

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

如果您正在使用适配器,并且没有指定路径或资源,则适配器将在内部搜索路径和资源 来自 Keycloak

第三步:

使用令牌端点向 得到或评估授予权限。可以使用 response_mode参数获取最终决策(是否提供访问)或检索整个权限。

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 "permission=Resource A#Scope A"

如果授权请求没有映射到任何权限,则返回一个 403 HTTP状态码。

我知道我来晚了一点,但是让我尽可能多地解释一下。

在密钥斗篷中,我们有这样的术语:

Resource : 用户将访问或执行操作的对象

Auth scope : 用户可以对特定对象执行的操作

政策 : 政策

权限 : 映射实际上发生在这里

如果您不想遵循手动方式,您可以导出这个 JSON 和所有的用户,资源,权限将自动设置布密钥斗篷

JSON 配置文件

现在让我们来看一个场景:

enter image description here

现在我们只有很少的资源,比如:

  1. 帐户
  2. 机器人
  3. 报告

我们希望实现只有特定用户才能执行特定操作的场景。

准备钥匙斗篷

创建一个新的领域

  1. 点击 添加领域按钮。

enter image description here

  1. 输入 Test-v1作为名称。
  2. 单击 Create。

enter image description here

创建新角色

  1. 点击 角色
  2. 点击 添加角色
  3. 创建角色“ admin”、“ agent”和“ super _ admin”

enter image description here

创建一个客户端

  • 单击 客户选项卡
  • 在客户端 ID 文本框中输入 应用程序客户端
  • 点击保存
  • 选择并再次选择客户端以配置其他设置
  • 验证客户端协议是否为 Openid-connect
  • 将访问类型设置为机密
  • 将启用的授权设置为打开
  • 最后点击 保存按钮。
  • 一个新的 授权选项卡将出现在顶部。
  • 在“授权”选项卡上选择,然后选择“设置”

检查决策策略是否设置为 全票通过。这是 资源服务器策略

enter image description here

创建自定义认证作用域

打开 授权标签 选择 授权范围 > 并单击 创造 在文本中输入 范围: 创建视野并保存值。

enter image description here

创建资源

  • 转到 资源标签现在 > ,并点击 创造
  • 逐一输入并创建以下资源 帐户 & 机器人 & 答复: 报告
  • 对于范围中的所有资源,文本选择我们早期创建的 范围: 创建视野的两个范围
  • 单击“保存”

enter image description here

制定政策

  • 再次在 Authorization 选项卡中,选择 政策
  • 单击 制定政策下拉菜单并选择 角色
  • 在“名称”文本框中,管理员
  • 在“领域角色”中选择角色 管理员
  • 检查逻辑设置为正
  • 单击 Save,对“ Agent”和“ Super _ admin”执行相同操作

enter image description here

  • 再次在 Authorization 选项卡中,选择 政策
  • 单击 制定政策下拉菜单并选择 聚集在一起
  • 在“名称”文本框中,管理员或超级管理员或代理
  • 在“领域角色”中选择角色 管理 & 超级管理 & 代理
  • 检查逻辑设置为 是的
  • 单击“保存” enter image description here

创建权限

  • 再次在 Authorization 选项卡中,选择 请求许可
  • 单击 创建权限下拉菜单并选择 基于范围
  • 在“名称”文本框中,创建帐户
  • 在资源框中,选择“资源: 帐户”
  • 在范围选择,范围: 创建
  • 应用策略 管理员
  • 我们必须按照需求以相同的方式为所有资源设置权限enter image description here

创建用户

  • 在 user 选项卡中创建一个 测试用户 我们不会为它分配任何角色、范围或组进行测试

我们来评估一下

  • 再次在 Authorization 选项卡中,选择 评估
  • 选择我们创建的客户端 应用程序客户端
  • 在用户中选择创建的用户 测试
  • 在角色中选择创建的用户 管理员
  • 资源价值,帐户
  • 点击 按钮
  • 点击 评估按钮

enter image description here

您将看到 Grant 是 允许,因为 管理员角色可以访问资源 帐户上的 创造风景操作。

让我们再次评估

  • 再次在 Authorization 选项卡中,选择 评估
  • 选择我们创建的客户端 应用程序客户端
  • 在用户中选择创建的用户 测试
  • 在角色中选择创建的用户 管理员
  • 资源价值,答复: 报告
  • 范围值,范围: 创建
  • 点击 按钮
  • 点击 评估按钮

enter image description here

您将看到 Grant 是 否认,因为只有 Super _ Admin角色可以访问资源 报告上的操作 创造

可以在这里找到具有资源、范围和权限的工作解决方案 密钥斗篷-nodejs-示例

只需使用使用 快速入门指南的 docker-compose 运行已经配置的钥匙斗篷即可。

项目中其他有用的例子

  • 自定义登录而不使用钥匙斗篷登录页。
  • 无状态 Node.js 服务器而不使用会话。
  • 用于检查权限的集中式中间件。未显式描述的路由无法访问。
  • 它可以用来为多个环境进行配置。例如ーー DEV,QA。
  • 使用 KeycaploxRESTAPI 创建用户、角色和自定义属性的示例。