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


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

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

创建客户端后,点右上角的 Action,然后选择 Download adapter config。对于 Format,请选择 *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-24.0.9.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 会话管理服务器端状态进行身份验证,则需要使用至少 存储 参数初始化 Keycloak (…​),从而传递 express-session 使用的实际会话存储。
    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 的代理后面运行,则必须根据 代理后面的表达 配置 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. 保护资源

简单身份验证
要强制用户在访问资源前必须经过身份验证,只需使用 keycloak.protect () 的 no-argument 版本:
    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 中定义的一组策略来保护资源及其特定方法/操作,从而从应用程序外部授权。这可以通过公开 keycloak.enforcer 方法来实现,您可以使用该方法来保护 resources metric
    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 设为 permissions (默认模式),服务器仅返回已授予权限的列表,而不发出新的访问令牌。除了没有发布新令牌外,此方法还会公开服务器通过 请求 授予的权限,如下所示:

    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_mode 是什么,keycloak.enforcer 方法都会首先尝试检查发送到应用程序的 bearer 令牌中的权限。如果 bearer 令牌已经执行了预期的权限,则不需要与服务器交互来获取决策。当您的客户端能够在访问受保护的资源前从具有预期权限的服务器获取访问令牌时,这特别有用,因此他们可以使用 Keycloak 授权服务(如增量授权服务)提供的一些功能,并避免对服务器的额外的请求。

默认情况下,策略实施器将使用定义为应用程序的 client_id (例如,通过 keycloak.json)来引用支持 Keycloak Authorization Services 的 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

当调用 user-triggered logout 时,可以传递查询参数 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 控制台的回调,以注销单个会话或所有会话。默认情况下,这些类型的管理回调相对于 / 的根 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