2.5. Red Hat build of Keycloak Node.js アダプター
Red Hat build of Keycloak は、サーバー側の JavaScript アプリケーションを保護するために Connect 上に構築された Node.js アダプターを提供します。これは、Express.js などのフレームワークと統合できる柔軟性を備えることが目的でした。
Node.js アダプターを使用するには、まず Red Hat build of Keycloak 管理コンソールでアプリケーションのクライアントを作成する必要があります。アダプターは、パブリック、機密、およびベアラーのみのアクセスタイプをサポートします。どちらを選択しても、ユースケースのシナリオにより異なります。
クライアントを作成したら、Installation
タブをクリックして、Format Option
の Red Hat build of Keycloak OIDC JSON
を選択し、Download
をクリックします。ダウンロードした keycloak.json
ファイルはプロジェクトの root ディレクトリーにあるはずです。
2.5.1. インストール
Node.js がすでにインストールされている場合は、アプリケーションのディレクトリーを作成します。
mkdir myapp && cd myapp
npm init
コマンドを使用して、アプリケーションの package.json
を作成します。次に、依存関係リストに Red Hat build of Keycloak 接続アダプターを追加します。
"dependencies": { "keycloak-connect": "file:keycloak-connect-22.0.13+redhat-00001.tgz" }
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 });
express-session
依存関係をインストールします。
npm install express-session
server.js
スクリプトを起動するには、package.json
の 'scripts' セクションに以下のコマンドを追加します。
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "node server.js" },
これで、以下のコマンドでサーバーを実行できるようになりました。
npm run start
デフォルトでは、これはアプリケーションの主な実行ファイルとともに keycloak.json
という名前のファイルを見つけ (ここではルートフォルダー)、Red Hat build of Keycloak 固有の設定を初期化します (公開鍵、レルム名、さまざまな URL など)。
この場合、Red Hat build of Keycloak 管理コンソールにアクセスするために Red Hat build of Keycloak デプロイメントが必要です。
Podman または Docker を使用して Red Hat build of Keycloak 管理コンソールをデプロイする方法の詳細は、それぞれのリンクを参照してください。
これで、Red Hat build of Keycloak Admin Console keycloak.json
ファイルを取得できます。
ダウンロードしたファイルをプロジェクトのルートディレクトリーに貼り付けます。
この方法を使用したインスタンス化により、妥当なデフォルトがすべて使用されます。または、keycloak.json
ファイルの代わりに、設定オブジェクトを指定することもできます。
const kcConfig = { clientId: 'myclient', bearerOnly: true, serverUrl: 'http://localhost:8080', realm: 'myrealm', realmPublicKey: 'MIIBIjANB...' }; const keycloak = new Keycloak({ store: memoryStore }, kcConfig);
アプリケーションは、以下を使用して、ユーザーを優先しているアイデンティティープロバイダーにリダイレクトすることもできます。
const keycloak = new Keycloak({ store: memoryStore, idpHint: myIdP }, kcConfig);
- Web セッションストアの設定
-
Web セッションを使用して認証のサーバー側の状態を管理する場合は、少なくとも
store
パラメーターで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 });
- カスタムスコープの値の指定
-
デフォルトでは、スコープ値の
openid
はクエリーパラメーターとして Red Hat build of Keycloak のログイン URL に渡されますが、さらにカスタム値を追加することができます。
const keycloak = new Keycloak({ scope: 'offline_access' });
2.5.3. ミドルウェアのインストール
インスタンス化したら、ミドルウェアを接続対応のアプリケーションにインストールします。
これを行うには、まず Express をインストールする必要があります。
npm install express
次に、以下で説明されているようにプロジェクトに Express が必要になります。
const express = require('express'); const app = express();
また、以下のコードを追加して Express で Keycloak ミドルウェアを設定します。
app.use( keycloak.middleware() );
最後に、以下のコードを main.js
に追加して、3000 ポートで HTTP 要求をリッスンするようにサーバーをセットアップしましょう。
app.listen(3000, function () { console.log('App listening on port 3000'); });
2.5.4. プロキシーの設定
SSL 接続を終了するプロキシーの背後でアプリケーション実行されている場合は、express behind proxies ガイドに従って、Express を設定する必要があります。誤ったプロキシー設定を使用すると、無効なリダイレクト URI が生成されることがあります。
設定例:
const app = express(); app.set( 'trust proxy', true ); app.use( keycloak.middleware() );
2.5.5. リソースの保護
- 簡易認証
-
リソースにアクセスする前にユーザーを認証する必要があるように強制するには、単に
keycloak.protect()
の非引数バージョンを使用します。
app.get( '/complain', keycloak.protect(), complaintHandler );
- ロールベースの認可
- 現在のアプリケーションのアプリケーションロールでリソースのセキュリティーを保護するには、以下を実行します。
app.get( '/special', keycloak.protect('special'), specialHandler );
別 のアプリケーションのアプリケーションロールでリソースを保護するには、以下を行います。
app.get( '/extra-special', keycloak.protect('other-app:special'), extraSpecialHandler );
レルムロールでリソースをセキュアにするには、以下を実行します。
app.get( '/admin', keycloak.protect( 'realm:admin' ), adminHandler );
- リソースベースの認可
-
リソースベースの認可を使用すると、Keycloak で定義された一連のポリシーに基づいて、リソースとその特定のメソッド/アクション ** を保護できるため、アプリケーションからの認可を外部化できます。これは、リソースを保護するために使用できる
keycloak.enforcer
メソッドを公開することで実現されます。*
app.get('/apis/me', keycloak.enforcer('user:profile'), userProfileHandler);
keycloak-enforcer
メソッドは、response_mode
設定オプションの値に応じて 2 つのモードで動作します。
app.get('/apis/me', keycloak.enforcer('user:profile', {response_mode: 'token'}), userProfileHandler);
response_mode
が token
に設定されている場合は、アプリケーションに送信されたベアラートークンで表されるサブジェクトの代わりにパーミッションがサーバーから取得されます。この場合、新しいアクセストークンは、サーバーによって付与されたアクセス許可を使用して、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 });
アプリケーションがセッションを使用していて、サーバーからの以前の決定をキャッシュし、更新トークンを自動的に処理する場合は、このモードが推奨されます。このモードは、クライアントとリソースサーバーとして動作するアプリケーションに特に便利です。
response_mode
が permissions
(デフォルトモード) に設定されている場合、サーバーは新しいアクセストークンを発行せずに付与されたパーミッションのリストのみを返します。このメソッドは、新しいトークンを発行しないだけでなく、以下のように リクエスト
を介してサーバーに付与されたパーミッションを公開します。
app.get('/apis/me', keycloak.enforcer('user:profile', {response_mode: 'permissions'}), function (req, res) { const permissions = req.permissions; // show user profile });
使用中の response_mode
に関係なく、keycloak.enforcer
メソッドは、アプリケーションに送信されたベアラートークン内のパーミッションを確認します。ベアラートークンで予想される権限がすでに引き継がれている場合は、サーバーと対話して意思決定を取得する必要はありません。これは、クライアントが、保護されたリソースにアクセスする前に予想されるパーミッションでサーバーからアクセストークンを取得できる場合に特に便利です。そのため、増分認可などの Keycloak Authorization Services が提供する機能を使用し、keycloak.enforcer
がリソースへのアクセスを強制している場合に、サーバーへの追加のリクエストを回避できます。
デフォルトでは、ポリシーエンフォーサーはアプリケーション (例: keycloak.json
) に定義された client_id
を使用して、Keycloak Authorization Services をサポートする Keycloak のクライアントを参照します。この場合、クライアントは実際にはリソースサーバーであることをパブリックにすることはできません。
アプリケーションがパブリッククライアント (フロントエンド) とリソースサーバー (バックエンド) の両方として機能している場合は、次の設定を使用して、適用するポリシーで Keycloak 内の別のクライアントを参照できます。
keycloak.enforcer('user:profile', {resource_server_id: 'my-apiserver'})
フロントエンドおよびバックエンドを表すために、Keycloak で個別のクライアントを使用することが推奨されます。
保護するアプリケーションが Keycloak 認可サービスで有効になり、keycloak.json
でクライアント認証情報を定義している場合は、サーバーに追加の要求をプッシュして決定のためにポリシーで利用できるようにすることができます。そのため、プッシュする要求と共に JSON を返す 関数
を想定する claims
設定オプションを定義できます。
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
Keycloak を設定してアプリケーションリソースを保護する方法の詳細は、認証サービスガイド を参照してください。
- 高度な認可
- URL 自体の一部に基づいてリソースを保護するには、各セクションにロールが存在することを前提としています。
function protectBySection(token, request) { return token.hasRole( request.params.section ); } app.get( '/:section/:page', keycloak.protect( protectBySection ), sectionHandler );
高度なログイン設定:
デフォルトでは、クライアントがベアラーのみでない限り、承認されていないすべてのリクエストは Red Hat build of Keycloak のログインページにリダイレクトされます。ただし、機密またはパブリッククライアントは、閲覧可能なエンドポイントと API エンドポイントの両方をホストする場合があります。認証されていない API 要求でのリダイレクトを防ぎ、代わりに HTTP 401 を返すようにするには、redirectToLogin 関数をオーバーライドします。
たとえば、このオーバーライドでは URL に /api/ が含まれているかどうかを確認し、ログインリダイレクトを無効にします。
Keycloak.prototype.redirectToLogin = function(req) { const apiReqMatcher = /\/api\//i; return !apiReqMatcher.test(req.originalUrl || req.url); };
2.5.6. 追加の URL
- 明示的なユーザーがトリガーされたログアウト
-
デフォルトでは、ミドルウェアは
/logout
への呼び出しをキャッチし、Red Hat build of Keycloak 中心のログアウトワークフローを介してユーザーを送信します。これは、logout
設定パラメーターをmiddleware()
呼び出しに指定することで変更できます。
app.use( keycloak.middleware( { logout: '/logoff' } ));
ユーザーがトリガーするログアウトが呼び出されると、クエリーパラメーター redirect_url
を渡すことができます。
https://example.com/logoff?redirect_url=https%3A%2F%2Fexample.com%3A3000%2Flogged%2Fout
次に、このパラメーターは OIDC ログアウトエンドポイントのリダイレクト URL として使用され、ユーザーは https://example.com/logged/out
にリダイレクトされます。
- Red Hat build of Keycloak 管理者コールバック
-
ミドルウェアは、Red Hat build of Keycloak コンソールのコールバックもサポートし、単一のセッションまたはすべてのセッションをログアウトします。デフォルトでは、これらの管理コールバックのタイプは
/
のルート URL に関連して行われますが、middleware()
呼び出しにadmin
パラメーターを指定して変更できます。
app.use( keycloak.middleware( { admin: '/callbacks' } );
2.5.7. 完全な例
Node.js アダプターの完全な使用例は、Keycloak quickstarts for Node.js にあります。