我知道我迟到了 2 年多,但我想我会分享我所知道的,并希望为未来的读者减轻一些痛苦。完全透明——我绝不是 Keycloak/OAuth/OIDC 专家,我所知道的主要来自阅读文档、书籍、优秀的 YouTube 和使用该工具。
这篇文章将由两部分组成:
- 我会尽力回答您的所有问题
- 我将向您展示如何在 Keycloak 中使用策略/范围/权限,而无需部署单独的应用程序,以便更好地理解此线程中的一些核心概念。请注意,这主要是为了让您开始。我正在使用
Keycloak 8.0.0。
第一部分
开始之前的一些术语:
- 在 Keycloak 中,您可以创建两种权限:Resource-Based 和 Scope-Based。
- 简单地说,对于
Resource-Based 权限,您直接将其应用于您的资源
- 对于
Scoped-Based 权限,您将其应用于您的范围或范围和资源。
最好的做法是只创建一个“视图”范围,并在多个资源(帐户、事务等)中使用它?还是应该创建“viewAccount”范围、“viewTransaction”范围等?
范围表示受保护资源的一组权限。在您的情况下,您有 2 个资源:account 和 transaction,所以我倾向于第二种方法。
从长远来看,拥有与所有资源相关联的全局 view 范围(例如 account、transaction、customer、settlement...)会使授权难以管理和适应安全要求的变化。
这里有一些示例,您可以查看以了解设计
请注意 - 我并不是说您不应该跨资源共享范围。事实上,Keycloak 允许对具有相同type 的资源执行此操作。例如,您可能需要viewAccount 和viewTransaction 范围来读取给定帐户下的交易(毕竟您可能需要访问该帐户才能查看交易)。您的要求和标准将严重影响您的设计。
对于资源和范围的每个实际组合,创建权限是通常的做法吗?
抱歉,我不完全理解这个问题,所以我会有点宽泛。要授予/拒绝对 resource 的访问权限,您需要:
让政策执行生效。见Authorization Process。
如何设置这一切完全取决于您。例如,您可以:
定义单独的策略,并在适当的权限下绑定每个策略。
更好的是,定义单个策略,然后将所有相关策略分组到 aggregated 策略(策略策略)下,然后将该聚合策略与 scope-based 权限相关联。您可以将 scoped-based 权限同时应用于资源及其所有关联范围。
或者,您可以通过利用这两种不同的类型来进一步分解您的权限。您可以通过resource-based 权限类型为您的资源单独创建权限,并通过scope-based 权限类型单独将其他权限与范围单独关联。
你有选择。
如果有多个权限匹配给定的资源/范围,Keycloak 会做什么?
这取决于
- 资源服务器的
Decision Strategy
- 每个权限的
Decision Strategy
- 每个策略的
Logic 值。
Logic 值类似于 Java 的 ! 运算符。它可以是Positive 或Negative。当Logic 为Positive 时,策略的最终评估保持不变。当它的Negative 时,最终结果被否定(例如,如果一个策略评估为假并且它的Logic 是Negative,那么它将是true)。为简单起见,我们假设Logic 始终设置为Positive。
Decision Strategy 是我们真正想要解决的问题。 Decision Strategy 可以是 Unanimous 或 Affirmative。从文档中,
决策策略
此配置更改了策略评估引擎根据所有评估权限的结果决定是否应授予资源或范围的方式。 肯定 意味着必须至少将一项权限评估为积极的决定,才能授予对资源及其范围的访问权限。 一致表示所有权限都必须评估为积极的决定,才能使最终决定也是积极的。例如,如果同一资源或范围的两个权限发生冲突(其中一个是授予访问权限,另一个是拒绝访问),如果选择的策略是肯定的,则将授予对该资源或范围的权限。否则,任何权限的单个拒绝也将拒绝对资源或范围的访问。
让我们用一个例子来更好地理解上面的内容。假设您有一个具有 2 个权限的资源,并且有人试图访问该资源(请记住,对于所有策略,Logic 是 Positive)。现在:
-
Permission One 有一个 Decision Strategy 设置为 Affirmative。它还有 3 个策略,每个策略都评估为:
由于其中一项政策设置为true,因此Permission One 设置为true(肯定 - 只需 1 项为 true)。
-
Permission Two 有一个 Decision Strategy 设置为 Unanimous,有 2 个策略:
在这种情况下,Permission Two 是 false,因为一个策略是错误的(一致 - 它们都需要是 true)。
- 现在是最终评估。如果资源服务器的
Decision Strategy 设置为Affirmative,则将授予对该资源的访问权限,因为Permission One 是true。另一方面,如果资源服务器的Decision Strategy 设置为Unanimous,则访问将被拒绝。
见:
我们将继续重新审视这一点。我在第二部分解释了如何设置资源服务器的Decision Strategy。
例如,我可以有权访问“帐户”和“查看”范围的权限,因此我将有权查看帐户吗?
简短的回答是肯定的。现在,让我们稍微扩展一下:)
如果你有以下情况:
- 资源服务器的
Decision Strategy 设置为Unanimous 或Affirmative
- 访问
account/{id}资源的权限是true
- 访问
view 范围的权限是true
您将被授予查看该帐户的权限。
-
true + true 等于true 在Affirmative 或Unanimous Decision Strategy 下。
如果你有这个
- 资源服务器的
Decision Strategy 设置为Affirmative
- 访问
account/{id}资源的权限是true
- 访问
view范围的权限是false
您将也被授予查看帐户的权限。
-
true + false 是true 在Affirmative 策略下。
这里的重点是,对给定资源的访问还取决于您的设置,因此请小心,因为您可能不希望出现第二种情况。
但这是否意味着我需要为用户可能属于的每个旧组制定策略?
我不确定 Keycloak 在 2 年前的表现如何,但您可以指定 Group-Based policy 并简单地将所有组添加到该策略下。您当然不需要为每个组创建一个策略。
例如,如果我有一个“帮助台”角色,那么我需要一个“帮助台成员”策略,然后我可以将其添加到“viewAccount”权限。这是正确的吗?
差不多。您可以通过多种方式进行设置。例如,您可以:
- 创建您的资源(例如
/account/{id})并将其与account:view 范围相关联。
- 创建一个Role-Based Policy 并在该策略下添加
helpdesk 角色
- 创建一个名为
viewAccount 的Scope-Based 权限并将其与scope、resource 和policy 绑定
我们将在第二部分设置类似的东西。
第二部分
Keycloak 有一个简洁的小工具,可让您测试所有策略。更好的是,您实际上不需要启动另一个应用程序服务器并部署一个单独的应用程序来工作。
这是我们将设置的场景:
- 我们将创建一个名为
stackoverflow-demo 的新领域
- 我们将在该领域下创建一个
bank-api 客户端
- 我们将为该客户端定义一个名为
/account/{id} 的资源
-
account/{id} 将具有 account:view 范围
- 我们将在新领域下创建一个名为
bob 的用户
- 我们还将创建三个角色:
bank_teller、account_owner 和 user
- 我们不会将
bob 与任何角色相关联。现在不需要这个。
- 我们将设置以下两个
Role-Based 策略:
-
bank_teller 和 account_owner 可以访问 /account/{id} 资源
-
account_owner 可以访问 account:view 范围
-
user 无权访问资源或范围
- 我们将使用
Evaluate 工具来了解如何授予访问权限或
否认。
请原谅我,这个例子不切实际,但我对银行业不熟悉:)
Keycloak 设置
下载并运行 Keycloak
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
创建初始管理员用户
- 转到
http://localhost:8080/auth
- 点击
Administration Console链接
- 创建管理员用户并登录
访问Getting Started 了解更多信息。对于我们的目的,以上内容就足够了。
搭建舞台
创建一个新领域
- 将鼠标悬停在
master 领域并单击Add Realm 按钮。
- 输入
stackoverflow-demo 作为名称。
- 点击
Create。
- 左上角现在应该显示
stackoverflow-demo 而不是master 领域。
见Creating a New Realm
创建一个新用户
- 点击左侧的
Users链接
- 点击
Add User按钮
- 输入
username(例如bob)
- 确保
User Enabled 已打开
- 点击
Save
见Creating a New User
创建新角色
- 点击
Roles链接
- 点击
Add Role
- 添加以下角色:
bank_teller、account_owner 和 user
同样,不要将您的用户与角色相关联。出于我们的目的,这不是必需的。
见Roles
创建客户端
- 点击
Clients链接
- 点击
Create
- 输入
bank-api 作为Client ID
- 对于
Root URL,输入http://127.0.0.1:8080/bank-api
- 点击
Save
- 确保
Client Protocol 是openid-connect
- 把
Access Type改成confidential
- 将
Authorization Enabled 更改为On
- 向下滚动并点击
Save。一个新的Authorization 选项卡应出现在顶部。
- 点击
Authorization 标签,然后点击Settings
- 确保将
Decision Strategy 设置为Unanimous
- 这是资源服务器的
Decision Strategy
见:
创建自定义范围
- 点击
Authorization标签
- 点击
Authorization Scopes>Create调出Add Scope页面
- 在名称中输入
account:view,然后按回车键。
创建“查看账户资源”
- 点击上方
Authorization链接
- 点击
Resources
- 点击
Create
- 为
Name 和Display name 输入View Account Resource
- 为
URI 输入account/{id}
- 在
Scopes 文本框中输入account:view
- 点击
Save
见Creating Resources
制定您的政策
- 再次在
Authorization 标签下,点击Policies
- 从
Create Policy 下拉列表中选择Role
- 在
Name 部分,输入Only Bank Teller and Account Owner Policy
- 在
Realm Roles 下选择bank_teller 和account_owner 角色
- 确保将
Logic 设置为Positive
- 点击
Save
- 点击
Policies链接
- 再次从
Create Policy 下拉列表中选择Role。
- 这次将
Only Account Owner Policy 用于Name
- 在
Realm Roles 下选择account_owner
- 确保将
Logic 设置为Positive
- 点击
Save
- 单击顶部的
Policies 链接,您现在应该会看到新创建的策略。
见Role-Based Policy
请注意,Keycloak 具有更强大的策略。见Managing Policies
创建基于资源的权限
- 再次在
Authorization 选项卡下,单击Permissions
- 选择
Resource-Based
- 为
Name 键入View Account Resource Permission
- 在
Resources 下输入View Account Resource Permission
- 在
Apply Policy 下选择Only Bank Teller and Account Owner Policy
- 确保将
Decision Strategy 设置为Unanimous
- 点击
Save
见Create Resource-Based Permissions
呼……
评估基于资源的权限
- 再次在
Authorization 选项卡下,选择Evaluate
- 在
User 下输入bob
- 在
Roles 下选择user
- 这是我们将我们的用户与我们创建的角色相关联的地方。
- 在
Resources 下选择View Account Resource 并单击Add
- 单击评估。
- 展开
View Account Resource with scopes [account:view] 以查看结果,您应该会看到DENY。
- 这是有道理的,因为我们只允许两个角色通过
Only Bank Teller and Account Owner Policy 访问该资源。让我们测试一下以确保这是真的!
- 点击评估结果正上方的
Back链接
- 将 bob 的角色更改为
account_owner 并单击 Evaluate。您现在应该看到结果为PERMIT。如果您返回并将角色更改为bank_teller,则同样的交易
见Evaluating and Testing Policies
创建基于范围的权限
- 返回
Permissions部分
- 这次在
Create Permission 下拉菜单下选择Scope-Based。
- 在
Name 下,输入View Account Scope Permission
- 在
Scopes 下,输入account:view
- 在
Apply Policy 下,输入Only Account Owner Policy
- 确保将
Decision Strategy 设置为Unanimous
- 点击
Save
见Creating Scope-Based Permissions
第二次试运行
评估我们的新变化
- 返回
Authorization部分
- 点击
Evaluate
- 用户应该是
bob
- 角色应该是
bank_teller
- 资源应为
View Account Resource 并单击Add
- 点击
Evaluate,我们应该得到DENY。
- 这也不足为奇,因为
bank_teller 可以访问resource,但不能访问scope。这里一个权限评估为真,另一个为假。鉴于资源服务器的Decision Strategy设置为Unanimous,最终决定为DENY。
- 单击
Authorization 选项卡下的Settings,将Decision Strategy 更改为Affirmative,然后再次返回步骤1-6。这一次,最终结果应该是PERMIT(一个权限是真的,所以最终决定是真的)。
- 为了完整起见,将资源服务器的
Decision Strategy 转回Unanimous。再次返回步骤 1 到 6,但这次将角色设置为 account_owner。这一次,最终结果还是PERMIT,这是有道理的,因为account_owner 可以同时访问resource 和scope。
整洁 :) 希望这会有所帮助。