第2章_保护您的第一个应用程序
第2章_保护您的第一个应用程序
在本章中,您将学习如何使用 Keycloak 保护您的第一个应用程序。为了让事情更有趣,您将运行的示例应用程序由两部分组成,前端 Web 应用程序和后端 REST API。这将向您展示用户如何向前端进行身份验证,以及它如何安全地调用后端。
在本章结束时,您将基本了解 Keycloak 如何利用 OpenID Connect 保护应用程序。
在本章中,我们将介绍以下主要主题:
理解示例应用程序
-
运行应用程序
-
了解如何登录应用程序
-
安全调用后端 REST API
技术要求
要运行本章中包含的示例应用程序,您需要在工作站上安装 Node. js(https://nodejs.org/)。
您还需要拥有与本书关联的 GitHub 存储库的本地副本。如果您安装了 Git,您可以通过在终端中运行以下命令来克隆存储库:
$ git clone https://github.com/PacktPublishing/Keycloak---Identity-and-Access-Management-for-Modern-Applications-2nd-Edition.git
或者,您可以从https://github.com/PacktPublishing/Keycloak—Identity-and-Access-Management-for-Modern-Applications-2nd-Edition下载存储库的 ZIP。
查看以下链接以查看 Code in Action 视频:https://packt.link/oxOr8
了解示例应用程序
示例应用程序由两部分组成 —— 前端 Web 应用程序和后端 REST API。
前端 Web 应用程序是一个用 JavaScript 编写的单页应用程序。由于我们想关注 Keycloak 可以提供什么,因此该应用程序非常简单。此外,为了使运行应用程序尽可能简单,它使用 Node. js。该应用程序提供以下功能:
-
使用 Keycloak 登录。
-
显示用户名。
-
会显示用户的个人资料图片(如果有)。
-
显示 ID 令牌。
-
显示访问令牌。
-
刷新令牌。
-
调用后端提供的安全端点。
后端 REST API 也很简单,是用 Node. js 实现的。它提供了一个具有两个端点的 REST API:
-
/public:没有安全性的公开可用端点
-
/secured:一个需要具有 myReal 全局角色的访问令牌的安全端点
Node. js 用于示例应用程序,因为我们希望使代码尽可能易于理解和运行,无论您熟悉什么编程语言。
下图显示了前端、后端和 Keycloak 之间的关系。前端使用 Keycloak 对用户进行身份验证,然后调用后端,后端使用 Keycloak 验证是否允许请求:
图 2.1:应用概述
现在您已经对示例应用程序有了基本的了解,让我们看一些关于这一切是如何结合在一起的更多细节。
当用户单击前端应用程序中的登录按钮时,浏览器将被重定向到 Keycloak 登录页面。然后,用户使用 Keycloak 进行身份验证,然后浏览器使用称为授权码的特殊代码重定向回应用程序。然后,应用程序调用 Keycloak 将授权码交换为以下令牌:
-
ID 令牌:这提供了与经过身份验证的用户有关的应用程序信息。
-
访问令牌:应用程序在向服务发出请求时包含此令牌,允许服务验证是否应允许请求。
-
刷新令牌:ID 和访问令牌都有很短的过期时间 —— 默认情况下为 5 分钟。应用程序使用刷新令牌从 Keycloak 获取新令牌。
描述的流程就是 OpenID Connect 中所谓的授权代码流程。如果您还不熟悉 OAuth 2.0 或 OpenID Connect,它们起初可能有点令人生畏,但一旦您熟悉它们,它们实际上非常简单易懂。
为了帮助可视化登录过程,提供了如下简化时序图:
图 2.2:简化的 OpenID Connect 中的授权代码流程
此图中的步骤如下:
-
用户点击登录按钮。
-
应用程序重定向到 Keycloak 登录页面。
-
Keycloak 登录页面显示给用户。
-
用户填写用户名和密码并将结果提交给 Keycloak。
-
验证用户名和密码后,Keycloak 将授权码发送给应用程序。
-
应用程序将授权码交换为 ID 令牌和访问令牌。应用程序现在可以通过检查 ID 令牌来验证用户的身份。
通过将用户的身份验证委托给 Keycloak,应用程序不必知道如何对用户进行身份验证。当身份验证机制发生变化时,这一点尤其重要。例如,无需更改应用程序即可启用双重验证。这也意味着应用程序无权访问用户的凭据。
与 Keycloak 相关的下一步是前端调用后端。后端 REST API 有一个受保护的端点,只能由具有全局角色 myorn 的用户调用。
为了完全准确,前端被授予代表用户调用后端的权限。这是 OAuth 2.0 美妙之处的一部分。应用程序没有权限做用户能够做的所有事情,只有它应该能够做的事情。
当前端向后端发出请求时,它会在请求中包含访问令牌。默认情况下,Keycloak 使用 JSON Web 签名(JWS)作为令牌格式。这些类型的令牌通常被称为非不透明令牌,这意味着令牌的内容对应用程序直接可见。
令牌还包括一个数字签名,使得验证令牌确实是由 Keycloak 发行的成为可能。本质上,这意味着后端可以验证令牌并读取内容,而无需向 Keycloak 发出请求,从而减少对 Keycloak 服务器的需求,并降低处理后端请求时的延迟。
为了帮助可视化前端向后端发送请求时会发生什么,请查看下图:
图 2.3:从前端到后端的安全请求简化
图中的步骤如下:
-
后端检索 Keycloak 的公钥。后端不需要对后端的所有请求执行此操作,而是可以将密钥缓存在内存中。
-
前端向后端发送请求,包括访问令牌。
-
后端使用之前检索到的公钥来验证访问令牌是否由受信任的 Keycloak 实例颁发,然后验证令牌是否有效并且令牌包含角色 my 角色。
-
后端将结果返回给前端。
您现在对如何使用 Keycloak 保护示例应用程序有了基本的了解。在下一节中,您将学习如何运行示例应用程序。
运行应用程序
在本节中,您将学习如何运行示例应用程序。
如果您的工作站上还没有安装 Node. js,请转到https://nodejs.org/以获取有关如何安装它的说明。
要在 Node.js 上运行前端,请打开终端并运行以下命令:
$ cd Keycloak---Identity-and-Access-Management-for-Modern-Applications-2nd-Edition/ch2/frontend/
$ npm install
$ npm start
接下来,使用以下命令打开一个新终端以运行后端:
$ cd Keycloak---Identity-and-Access-Management-for-Modern-Applications-2nd-Edition/ch2/backend/
$ npm install
$ npm start
现在您已经使用 Node. js 运行了示例应用程序,您可以使用 Keycloak 注册它,我们将在下一节中介绍。
了解如何登录应用程序
在上一章中,介绍了如何开始使用 Keycloak,您学习了如何运行 Keycloak,以及如何创建您的第一个领域。在继续本节之前,您应该让 Keycloak 在创建的领域中运行,如上一章所述。总之,在继续之前,您需要以下内容:
-
Keycloak启动并运行
-
一个为myrealm的领域
-
一个为 myrole 的全局角色
-
具有上述角色的用户
在应用程序可以使用 Keycloak 登录之前,它必须使用 Keycloak 注册为客户端。在注册前端之前,让我们看看如果未注册的应用程序尝试使用 Keycloak 进行身份验证会发生什么。打开http://localhost:8000,然后单击登录按钮。您将看到来自 Keycloak 的错误页面,其中显示未找到客户端消息。此错误告诉您该应用程序未使用 Keycloak 注册。
要使用 Keycloak 注册前端,请打开 Keycloak 管理控制台。在左侧菜单的顶部,有一个选项可以选择您正在使用的领域。确保您选择了名为 mydomain 的领域。在左侧菜单中,单击客户端,然后单击创建客户端。
用以下值填写表单:
- Client ID:myclient
填写 Client ID 字段后,单击 Next。在以下屏幕上,可以启用和禁用应用程序所需的各种功能。现在,您可以简单地忽略此步骤并单击保存。
在前端应用程序可以使用客户端使用 Keycloak 进行身份验证之前,您必须注册应用程序的 URL。在访问设置下,填写以下值:
- Valid redirect URIs: http://localhost:8000/
- Valid post redirect URIs: http://localhost:8000/
- Web origins: http://localhost:8000
填写表单后,单击保存。在我们继续尝试使用前端应用程序登录之前,让我们进一步了解您输入的最后一个配置值的含义:
-
Valid redirect URIs:当使用客户端应用程序时,此值在 OpenID Connect 授权代码流中非常重要。客户端应用程序无法拥有任何凭据,因为它们对应用程序的最终用户是可见的。为了防止任何恶意应用程序伪装成真正的应用程序,有效的重定向 URI 指示 Keycloak 仅将用户重定向到与有效重定向 URI 匹配的 URL。在这种情况下,由于该值设置为
-
Valid post redirect URIs:用于配置登出请求的重定向 URL,和登录时的重定向 URL 类似。Keycloak 支持设置特殊值 “+” ,表示允许所有有效的重定向 URI 作为登出时的重定向地址。
-
Web origins:此选项为跨域资源共享(CORS)请求注册应用程序的有效 Web 来源。要从 Keycloak 获取令牌,前端应用程序必须向 Keycloak 发送 AJAX 请求,浏览器不允许从一个 Web 来源到另一个 Web 来源的 AJAX 请求,除非使用 CORS。Keycloak 支持添加一个值为 + 的特殊 Web 来源,这导致允许所有有效的重定向 URI 作为 Web 来源。
以下屏幕截图显示了 Keycloak 管理控制台中创建的客户端。
图 2.4:管理控制台中的客户端设置
现在您可以通过打开http://localhost:8000返回前端。这次,当您单击登录按钮时,您将看到 Keycloak 登录页面。使用您在上一章中创建的用户名和密码登录。
让我们看看 Keycloak 发行的 ID 令牌。单击 Show ID Token 按钮。显示的 ID 令牌如下所示:
{
"exp": 1664300152,
"iat": 1664299852,
"auth_time": 1664298915,
"jti": "21bb9f32-98ce-49aa-896d-796cb716be59",
"iss": "http://localhost:8080/realms/myrealm",
"aud": "myclient",
"sub": "eb14ea82-45e2-4413-8997-129fd0fc865b",
"typ": "ID",
"azp": "myclient",
"nonce": "ccf5f374-aa07-4280-b63a-efdba9c355c9",
"session_state": "22884115-55cb-4285-ba92-26c4bf74f74b",
"at_hash": "ngdMORpXQcEQJ6d9s3uHvw",
"acr": "0",
"sid": "22884115-55cb-4285-ba92-26c4bf74f74b",
"email_verified": true,
"name": "Stian Thorgersen",
"preferred_username": "st",
"given_name": "Stian",
"family_name": "Thorgersen",
"email": "st@localdomain.localhost"
}
以下是 ID 令牌中一些更有趣的值的列表:
-
exp:这是自 01/01/197000:00:00 UTC(通常称为 Unix 或 Epoch 时间)以来令牌以秒为单位到期的日期和时间。
-
ISS:这是令牌的发行者,您可能会注意到它是 Keycloak 领域的 URL。这个信息有助于验证令牌的来源可靠性,应用可以通过确认 iss 字段的值是否是信任的 Keycloak 领域 URL,来判断该令牌是否是由合法的 Keycloak 实例颁发的,从而增强认证的安全性。
-
sub:这是经过身份验证的用户的唯一标识符。在整个系统中,无论用户的其他信息(如用户名、姓名等)如何变化,sub 字段始终保持不变,具有稳定性和唯一性。因此在应用开发中,常将 sub 字段作为识别用户的关键标识,用于关联用户的各类数据和权限信息。
-
name:这是经过身份验证的用户的名字和姓氏。用于直观展示用户的姓名信息。在一些需要显示用户真实姓名的场景,如用户个人资料页面、欢迎提示等地方,这个字段提供了直接可用的用户姓名数据。
-
preferred_username:代表认证用户的用户名,但不建议将其作为用户的唯一标识或关键引用。因为用户名具有可变性,用户可能会更改自己的用户名,而且在某些情况下,可能会出现用户名被重新分配给其他用户的情况。相比之下,sub 字段更适合作为用户的唯一标识,在涉及用户身份验证、权限管理和数据关联等操作时,使用 sub 字段能确保数据的准确性和一致性 。
应用程序使用 ID 令牌来建立经过身份验证的用户的身份。
接下来,让我们看看访问令牌。单击显示访问令牌按钮。让我们也看看这个令牌中的一些字段:
-
allowed-origins:这是应用程序允许的 Web 来源列表。后端服务在决定是否应允许 CORS 请求使用 Web 来源时可以使用此字段。
-
realm_access:这包含全局领域角色列表。它是授予用户的角色和客户端有权访问的角色之间的交集。
-
resource_access:包含客户端角色列表,用于确定用户在特定客户端相关资源上的访问权限,与具体客户端的资源访问控制紧密相关。
-
scope:作用有两个,一是决定令牌中包含哪些字段或声明;二是供后端判断该令牌可以访问哪些 API,在控制 API 访问权限方面发挥关键作用。
目前,令牌中的信息是 Keycloak 中可用的默认字段。如果您想添加其他信息,Keycloak 非常灵活,允许您自定义令牌中的内容。
让我们通过为用户添加图片来尝试一下。保持前端打开的选项卡,然后使用 Keycloak 管理控制台打开一个新选项卡。在左侧的菜单中,单击Users,并选择您之前创建的用户。现在让我们为用户添加一个自定义属性。单击Attributes。在表格中,底部将有两个空的输入字段。在关键列中,将值设置为图片,在值列中,将值设置为个人资料图片的 URL(在下面的屏幕截图中,我使用了我的 GitHub 头像)。然后,单击Save。
图 2.5:向用户添加自定义属性
现在,回到打开前端的选项卡。要显示个人资料图片,您可以单击刷新按钮。当您单击此按钮时,令牌将被刷新,新的 ID 令牌现在将包含您刚刚添加的图片属性,它允许应用程序为用户显示个人资料图片。
接下来,您将学习如何从前端安全地调用后端。
安全调用后端 REST API
现在,打开http://localhost:3000/并单击公共端点链接。您将看到一条消息说Public message!。公共端点不受 Keycloak 保护,无需访问令牌即可调用。
接下来,让我们尝试受 Keycloak 保护的安全端点。再次打开http://localhost:3000。这一次,单击安全端点链接。现在您将看到一条消息说 Access denied.。此请求不允许,因为它需要有效的访问令牌来调用端点。
现在让我们尝试从前端调用安全端点。打开http://localhost:8000/并单击调用服务。您现在将看到一条消息显示Secret message!。如果相反,您收到消息Access Denied,这很可能是由用户没有 my 角色引起的。
当单击调用服务时,前端会向后端服务发送 AJAX 请求,包括请求中的访问令牌,这允许后端验证调用是否代表具有访问端点所需角色的用户完成。
小结
在本章中,您学习了如何保护您的第一个应用程序,该应用程序由前端 Web 应用程序和带有 Keycloak 的后端 REST API 组成。您还基本了解了 Keycloak 如何利用 OpenID Connect 以标准和安全的方式实现这一切。加上您在本书第一章中学到的知识,您现在已经有了开始学习更多关于 Keycloak 的坚实基础。
在下一章中,我们将深入探讨使用 Keycloak 保护应用程序,让您更好地了解它是如何工作的。
问题
-
应用程序如何使用 Keycloak 进行身份验证?
-
您需要在 Keycloak 管理控制台中配置什么才能允许应用程序使用 Keycloak 进行身份验证?
-
应用程序如何安全地调用受保护的后端服务?