2.5. 红帽构建的 Keycloak Node.js 适配器


Red Hat build of Keycloak 提供了一个在 Connect 上构建的 Node.js 适配器,以保护服务器端 JavaScript 应用 - 目标足够灵活,以便与 Express.js 等框架集成。

要使用 Node.js 适配器,您必须首先在红帽构建的 Keycloak 管理控制台中为应用程序创建一个客户端。适配器支持 public、Conf 和 bearer-only 访问类型。哪个选择取决于用例。

创建客户端后,点 Installation 选项卡,为 Format Option 选择 Red Hat build of Keycloak OIDC JSON,然后点 Download。下载的 keycloak.json 文件应位于项目的根目录中。

2.5.1. 安装

假设您已安装了 Node.js,请为您的应用程序创建一个文件夹:

mkdir myapp && cd myapp
Copy to Clipboard Toggle word wrap

使用 npm init 命令为您的应用程序创建 package.json。现在,在依赖项列表中添加红帽构建的 Keycloak 连接适配器:

    "dependencies": {
        "keycloak-connect": "file:keycloak-connect-22.0.13+redhat-00001.tgz"
    }
Copy to Clipboard Toggle word wrap

2.5.2. 使用方法

实例化 Keycloak 类
Keycloak 类为配置并与您的应用程序集成提供了一个中央点。最简单的创建涉及任何参数。

在项目的根目录中,创建一个名为 server.js 的文件并添加以下代码:

    const session = require('express-session');
    const Keycloak = require('keycloak-connect');

    const memoryStore = new session.MemoryStore();
    const keycloak = new Keycloak({ store: memoryStore });
Copy to Clipboard Toggle word wrap

安装 express-session 依赖项:

    npm install express-session
Copy to Clipboard Toggle word wrap

要启动 server.js 脚本,请在 package.json 的 'scripts' 部分添加以下内容:

    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "start": "node server.js"
    },
Copy to Clipboard Toggle word wrap

现在,我们可以使用以下命令运行服务器:

    npm run start
Copy to Clipboard Toggle word wrap

默认情况下,这将找到一个名为 keycloak.json 的文件,以及应用程序的主可执行文件(在根文件夹上),以初始化红帽构建的 Keycloak 特定设置,如公钥、域名、各种 URL。

在这种情况下,红帽构建的 Keycloak 部署需要访问红帽构建的 Keycloak 管理控制台。

请访问有关如何使用 PodmanDocker部署红帽构建的 Keycloak 管理控制台的链接

现在,我们已准备好通过访问 Red Hat build of Keycloak Admin Console client (left sidebar)→ 选择您的 client Installation Format Option Keycloak OIDC JSON Download

将下载的文件粘贴到我们的项目的根目录上。

使用此方法进行实例化会导致所有合理的默认值都被使用。另外,也可以提供配置对象,而不是 keycloak.json 文件:

    const kcConfig = {
        clientId: 'myclient',
        bearerOnly: true,
        serverUrl: 'http://localhost:8080',
        realm: 'myrealm',
        realmPublicKey: 'MIIBIjANB...'
    };

    const keycloak = new Keycloak({ store: memoryStore }, kcConfig);
Copy to Clipboard Toggle word wrap

应用程序也可以使用以下方法将用户重定向到首选身份提供程序:

    const keycloak = new Keycloak({ store: memoryStore, idpHint: myIdP }, kcConfig);
Copy to Clipboard Toggle word wrap
配置 Web 会话存储
如果要使用 Web 会话来管理服务器端状态进行身份验证,则需要至少使用 store 参数初始化 Keycloak (…​),传递 表达会话使用的实际会话 存储。
    const session = require('express-session');
    const memoryStore = new session.MemoryStore();

    // Configure session
    app.use(
      session({
        secret: 'mySecret',
        resave: false,
        saveUninitialized: true,
        store: memoryStore,
      })
    );

    const keycloak = new Keycloak({ store: memoryStore });
Copy to Clipboard Toggle word wrap
传递自定义范围值
默认情况下,范围值 openid 作为查询参数传递给红帽构建的 Keycloak 登录 URL,但您可以添加额外的自定义值:
    const keycloak = new Keycloak({ scope: 'offline_access' });
Copy to Clipboard Toggle word wrap

2.5.3. 安装中间件

实例化后,将中间件安装到支持连接的应用程序中:

为此,首先需要安装 Express:

    npm install express
Copy to Clipboard Toggle word wrap

然后,在项目中需要 Express,如下所示:

    const express = require('express');
    const app = express();
Copy to Clipboard Toggle word wrap

并通过在以下代码中添加并在 Express 中配置 Keycloak 中间件:

    app.use( keycloak.middleware() );
Copy to Clipboard Toggle word wrap

最后,通过将以下代码添加到 main.js,使服务器设置为侦听端口 3000 上的 HTTP 请求:

    app.listen(3000, function () {
        console.log('App listening on port 3000');
    });
Copy to Clipboard Toggle word wrap

2.5.4. 代理配置

如果应用程序在终止 SSL connection Express 的代理后面运行,则必须根据 代理指南后面的表达 进行配置。使用不正确的代理配置可能会导致生成无效的重定向 URI。

配置示例:

    const app = express();

    app.set( 'trust proxy', true );

    app.use( keycloak.middleware() );
Copy to Clipboard Toggle word wrap

2.5.5. 保护资源

简单身份验证
要强制用户在访问资源前验证用户,只需使用 no-argument 版本 keycloak.protect ()
    app.get( '/complain', keycloak.protect(), complaintHandler );
Copy to Clipboard Toggle word wrap
基于角色的授权
使用当前应用程序的应用程序角色保护资源:
    app.get( '/special', keycloak.protect('special'), specialHandler );
Copy to Clipboard Toggle word wrap

使用不同应用程序的应用程序角色 保护资源

    app.get( '/extra-special', keycloak.protect('other-app:special'), extraSpecialHandler );
Copy to Clipboard Toggle word wrap

使用 realm 角色保护资源:

    app.get( '/admin', keycloak.protect( 'realm:admin' ), adminHandler );
Copy to Clipboard Toggle word wrap
基于资源的授权
基于资源的授权允许您保护资源,并根据 Keycloak 中定义的一组策略来保护资源及其特定方法/actions,从而从外部化应用程序中的授权。这可以通过公开一个 keycloak.enforcer 方法来实现,您可以使用它来保护资源 192.168.1.0/24
    app.get('/apis/me', keycloak.enforcer('user:profile'), userProfileHandler);
Copy to Clipboard Toggle word wrap

keycloak-enforcer 方法在两个模式下运行,具体取决于 response_mode 配置选项的值。

    app.get('/apis/me', keycloak.enforcer('user:profile', {response_mode: 'token'}), userProfileHandler);
Copy to Clipboard Toggle word wrap

如果将 response_mode 设置为 令牌,则权限代表发送到应用程序的 bearer 令牌代表从服务器获得。在这种情况下,Keycloak 会发布一个新的访问令牌,其权限由服务器授予。如果服务器没有响应具有预期权限的令牌,请求将被拒绝。使用此模式时,您应该能够从请求获取令牌,如下所示:

    app.get('/apis/me', keycloak.enforcer('user:profile', {response_mode: 'token'}), function (req, res) {
        const token = req.kauth.grant.access_token.content;
        const permissions = token.authorization ? token.authorization.permissions : undefined;

        // show user profile
    });
Copy to Clipboard Toggle word wrap

当应用程序使用会话且您想要从服务器缓存以前的决策时,首选这种模式,并自动处理刷新令牌。这个模式对于充当客户端和服务器的应用程序特别有用。

如果将 response_mode 设为 权限 (默认模式),服务器只返回授予的权限列表,而不发出新的访问令牌。除了不发布新令牌外,此方法还通过 请求 公开服务器授予的权限,如下所示:

    app.get('/apis/me', keycloak.enforcer('user:profile', {response_mode: 'permissions'}), function (req, res) {
        const permissions = req.permissions;

        // show user profile
    });
Copy to Clipboard Toggle word wrap

无论正在使用中的 response_modekeycloak.enforcer 方法都将首先尝试检查发送到应用程序的 bearer 令牌中的权限。如果 bearer 令牌已经获得预期权限,则不需要与服务器交互来获取决策。当您的客户端能够在访问受保护的资源前从具有所需权限的服务器获取访问令牌时,这特别有用,因此它们可以使用 Keycloak 授权服务提供的一些功能,如增量授权,并在 keycloak.enforcer 强制访问资源时从服务器获取访问令牌。

默认情况下,策略 enforcer 将使用定义为应用程序(例如,通过 keycloak.json)定义的 client_id 来引用支持 Keycloak 授权服务的 Keycloak 中的客户端。在这种情况下,客户端不能是公共的,表示它实际上是一个资源服务器。

如果您的应用程序同时充当公共客户端(frontend)和资源服务器(backend),您可以使用以下配置引用 Keycloak 中的不同客户端,以及您要强制执行的策略:

      keycloak.enforcer('user:profile', {resource_server_id: 'my-apiserver'})
Copy to Clipboard Toggle word wrap

建议您在 Keycloak 中使用不同的客户端来代表您的前端和后端。

如果您使用 Keycloak 授权服务启用了您要保护的应用程序,且您在 keycloak.json 中定义客户端凭证,您可以将其他声明推送到服务器,并将其提供给您的策略,以便做出决策。为此,您可以定义一个 claims 配置选项,它需要一个会返回一个带有您要推送的声明的 JSON 的函数

      app.get('/protected/resource', keycloak.enforcer(['resource:view', 'resource:write'], {
          claims: function(request) {
            return {
              "http.uri": ["/protected/resource"],
              "user.agent": // get user agent  from request
            }
          }
        }), function (req, res) {
          // access granted
Copy to Clipboard Toggle word wrap

有关如何配置 Keycloak 以保护应用程序资源的详情,请参考 授权服务指南

高级授权
要根据 URL 本身的部分保护资源,假设每个部分都有一个角色:
    function protectBySection(token, request) {
      return token.hasRole( request.params.section );
    }

    app.get( '/:section/:page', keycloak.protect( protectBySection ), sectionHandler );
Copy to Clipboard Toggle word wrap

高级登录配置:

默认情况下,除非您的客户端为 bearer-only,否则所有未授权的请求都会被重定向到红帽构建的 Keycloak 登录页面。但是,机密或公共客户端可以同时托管可浏览和 API 端点。要防止对未经身份验证的 API 请求重定向,而是返回 HTTP 401,您可以覆盖 redirectToLogin 功能。

例如,此覆盖检查 URL 是否包含 /api/,并禁用登录重定向:

    Keycloak.prototype.redirectToLogin = function(req) {
    const apiReqMatcher = /\/api\//i;
    return !apiReqMatcher.test(req.originalUrl || req.url);
    };
Copy to Clipboard Toggle word wrap

2.5.6. 其他 URL

用户触发的退出方式
默认情况下,中间件会捕获对 /logout 的调用,以便通过以 Keycloak 为中心的注销工作流向用户发送。这可以通过在 middleware() 调用中指定 logout 配置参数来更改:
    app.use( keycloak.middleware( { logout: '/logoff' } ));
Copy to Clipboard Toggle word wrap

当用户触发的注销被调用查询参数 redirect_url 时,可以传递:

https://example.com/logoff?redirect_url=https%3A%2F%2Fexample.com%3A3000%2Flogged%2Fout
Copy to Clipboard Toggle word wrap

然后,这个参数用作 OIDC 注销端点的重定向 URL,用户将重定向到 https://example.com/logged/out

红帽构建的 Keycloak 管理回调
另外,中间件还支持来自红帽构建的 Keycloak 控制台的回调,以注销单个会话或所有会话。默认情况下,这些类型的 admin 回调相对于 / 的 root URL,但可以通过向 middleware () 调用提供 admin 参数来更改:
    app.use( keycloak.middleware( { admin: '/callbacks' } );
Copy to Clipboard Toggle word wrap

2.5.7. 完成示例

使用 Node.js 适配器使用的完整示例可在 Node.js 的 Keycloak 快速入门中找到

返回顶部
Red Hat logoGithubredditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。 了解我们当前的更新.

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

Theme

© 2025 Red Hat