WordPress-RAG SSO連携 要件定義書
| 項目 |
内容 |
| 作成日 |
2024年12月24日 |
| バージョン |
1.0 |
| ステータス |
承認済み |
1. 概要
1.1 目的
WordPress PWAアプリケーションにログイン済みのユーザーが、別ドメインで稼働するRAGシステム(KnowledgeYard)に自動的にログインできるSSO(シングルサインオン)連携を実現する。
1.2 スコープ
| 機能 |
優先度 |
担当 |
| SSO連携(トークン発行・受け取り) |
P1 |
WordPress + RAG |
| ユーザー一括インポート |
P1 |
RAG |
| 部署ベース権限制御 |
P2 |
RAG |
| 文書権限管理UI |
P2 |
RAG |
1.3 システム構成
┌─────────────────────────────────┐ ┌─────────────────────────────────┐
│ WordPress PWA │ │ RAGシステム (KnowledgeYard) │
│ (別ドメイン) │ │ (別ドメイン) │
├─────────────────────────────────┤ ├─────────────────────────────────┤
│ │ │ │
│ ・社員番号でログイン │ │ ・Azure Functions API │
│ ・1600名(関連会社含む) │ │ ・Azure AI Search │
│ ・本社280名がRAG利用対象 │ │ ・Azure Table Storage │
│ ・部署情報を管理・調整 │ │ ・React フロントエンド │
│ │ │ │
└─────────────────────────────────┘ └─────────────────────────────────┘
│ │
│ SSO連携フロー │
│◀─────────────────────────────────────▶│
│ │
2. SSO連携仕様
2.1 認証フロー
[WordPress] [RAGシステム]
│ │
│ ① ユーザーがWordPressにログイン済み │
│ │
│ ② 「RAG検索」ボタンをクリック │
│ ↓ │
│ ③ PHP: 署名付きリクエストを生成 │
│ - user_id (社員番号) │
│ - timestamp (UNIX時間) │
│ - signature (HMAC-SHA256) │
│ ↓ │
│ ④ POST /api/auth/sso-token ──────────→ │
│ │ ⑤ 署名を検証
│ │ ⑥ タイムスタンプ有効期限チェック(5分)
│ │ ⑦ ユーザー存在確認
│ │ - 存在しない → エラー返却
│ │ - 存在する → JWTトークン生成
│ ⑧ JWTトークン受信 ←─────────────────── │
│ ↓ │
│ ⑨ 新規タブでRAGを開く │
│ URL: https://rag.example.com?sso_token=xxx
│ │ ⑩ URLパラメータからトークン取得
│ │ ⑪ トークンをlocalStorageに保存
│ │ ⑫ URLからパラメータを削除
│ │ ⑬ 認証済み状態でアプリ表示
2.2 共有シークレット
| 項目 |
値 |
| 名称 |
SSO_SHARED_SECRET |
| 形式 |
64文字以上のランダム文字列 |
| 設定場所(WordPress) |
wp-config.php または環境変数 |
| 設定場所(RAG) |
Azure Functions アプリケーション設定 |
重要: 本番環境では安全な方法でシークレットを共有してください。
2.3 署名生成アルゴリズム
signature = HMAC-SHA256(
key: SSO_SHARED_SECRET,
message: "{user_id}:{timestamp}"
)
user_id: 社員番号(文字列)
timestamp: UNIX時間(秒)
- 署名は16進数文字列(小文字)で送信
3. API仕様
3.1 SSOトークン発行 API
【RAG側で実装】
| 項目 |
内容 |
| エンドポイント |
POST /api/auth/sso-token |
| 認証 |
不要(署名で認証) |
リクエスト
{
"user_id": "12345",
"timestamp": 1703404800,
"signature": "a1b2c3d4e5f6..."
}
| フィールド |
型 |
必須 |
説明 |
| user_id |
string |
✅ |
社員番号 |
| timestamp |
integer |
✅ |
UNIX時間(秒) |
| signature |
string |
✅ |
HMAC-SHA256署名(16進数) |
レスポンス(成功: 200)
{
"token": "eyJhbGciOiJIUzI1NiIs...",
"user": {
"user_id": "12345",
"display_name": "山田太郎",
"role": "user",
"department": "総務部",
"email": "yamada@example.com"
},
"expires_in": 86400
}
レスポンス(エラー)
| HTTPステータス |
エラーコード |
説明 |
| 400 |
INVALID_REQUEST |
リクエスト形式が不正 |
| 401 |
INVALID_SIGNATURE |
署名が一致しない |
| 401 |
EXPIRED_TIMESTAMP |
タイムスタンプが期限切れ(5分超過) |
| 404 |
USER_NOT_FOUND |
ユーザーが登録されていない |
{
"error": {
"code": "USER_NOT_FOUND",
"message": "指定されたユーザーは登録されていません"
}
}
3.2 ユーザー一括インポート API
【RAG側で実装】
| 項目 |
内容 |
| エンドポイント |
POST /api/manage/users/bulk |
| 認証 |
Bearer Token(adminロール必須) |
リクエスト
{
"users": [
{
"user_id": "12345",
"display_name": "山田太郎",
"department": "総務部",
"email": "yamada@example.com",
"role": "user"
},
{
"user_id": "12346",
"display_name": "鈴木花子",
"department": "人事部",
"email": "suzuki@example.com",
"role": "user"
}
],
"update_existing": true
}
| フィールド |
型 |
必須 |
説明 |
| users |
array |
✅ |
ユーザー情報の配列(最大100件) |
| users[].user_id |
string |
✅ |
社員番号 |
| users[].display_name |
string |
✅ |
表示名(氏名) |
| users[].department |
string |
❌ |
部署名 |
| users[].email |
string |
❌ |
メールアドレス |
| users[].role |
string |
❌ |
ロール(デフォルト: "user") |
| users[].password |
string |
❌ |
パスワード(省略時: user_idと同じ) |
| update_existing |
boolean |
❌ |
true: 既存ユーザーを更新(デフォルト: false) |
レスポンス(成功: 200 または 207)
{
"created": 45,
"updated": 5,
"skipped": 0,
"errors": [
{
"index": 50,
"user_id": "99999",
"error": "display_name is required"
}
],
"total_requested": 51
}
4. WordPress側 実装要件
4.1 SSO連携機能
4.1.1 設定ファイル
// wp-config.php に追加
define('RAG_SSO_SECRET', 'your-64-character-secret-key-here...');
define('RAG_API_URL', 'https://rag.example.com/api');
define('RAG_APP_URL', 'https://rag.example.com');
4.1.2 SSOトークン取得関数
<?php
/**
* RAGシステム用のSSOトークンを取得する
*
* @param string $user_id 社員番号
* @return array|WP_Error トークン情報またはエラー
*/
function get_rag_sso_token($user_id) {
$timestamp = time();
$message = $user_id . ':' . $timestamp;
$signature = hash_hmac('sha256', $message, RAG_SSO_SECRET);
$response = wp_remote_post(RAG_API_URL . '/auth/sso-token', [
'headers' => [
'Content-Type' => 'application/json',
],
'body' => json_encode([
'user_id' => $user_id,
'timestamp' => $timestamp,
'signature' => $signature,
]),
'timeout' => 30,
]);
if (is_wp_error($response)) {
return $response;
}
$status_code = wp_remote_retrieve_response_code($response);
$body = json_decode(wp_remote_retrieve_body($response), true);
if ($status_code !== 200) {
return new WP_Error(
$body['error']['code'] ?? 'UNKNOWN_ERROR',
$body['error']['message'] ?? 'RAGシステムへの接続に失敗しました'
);
}
return $body;
}
4.1.3 RAG起動ボタン/リンクの実装
<?php
/**
* RAGシステムを開くURLを生成する
* ログインユーザーの社員番号を使用
*/
function get_rag_launch_url() {
if (!is_user_logged_in()) {
return null;
}
$current_user = wp_get_current_user();
$user_id = $current_user->user_login; // 社員番号
$result = get_rag_sso_token($user_id);
if (is_wp_error($result)) {
// エラーログ記録
error_log('RAG SSO Error: ' . $result->get_error_message());
return null;
}
$token = $result['token'];
return RAG_APP_URL . '?sso_token=' . urlencode($token);
}
/**
* RAG起動ボタンのショートコード
* 使用例: [rag_button text="RAG検索を開く"]
*/
function rag_button_shortcode($atts) {
$atts = shortcode_atts([
'text' => 'RAG検索',
'class' => 'rag-launch-button',
], $atts);
$url = get_rag_launch_url();
if (!$url) {
return '<span class="rag-error">RAGシステムを利用できません</span>';
}
return sprintf(
'<a href="%s" target="_blank" class="%s" rel="noopener noreferrer">%s</a>',
esc_url($url),
esc_attr($atts['class']),
esc_html($atts['text'])
);
}
add_shortcode('rag_button', 'rag_button_shortcode');
4.1.4 JavaScript版(AJAX対応)
/**
* RAGシステムを新規タブで開く
* トークンを取得してからURLにパラメータ付きで開く
*/
async function openRAGSystem() {
try {
const response = await fetch('/wp-json/rag/v1/get-token', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': wpApiSettings.nonce,
},
});
if (!response.ok) {
const error = await response.json();
alert(error.message || 'RAGシステムへの接続に失敗しました');
return;
}
const data = await response.json();
const ragUrl = `${RAG_APP_URL}?sso_token=${encodeURIComponent(data.token)}`;
window.open(ragUrl, '_blank', 'noopener,noreferrer');
} catch (error) {
console.error('RAG SSO Error:', error);
alert('RAGシステムへの接続に失敗しました');
}
}
4.2 ユーザーCSVエクスポート
月次インポート用に、本社280名のユーザー情報をCSV出力する機能が必要です。
4.2.1 CSVフォーマット
社員番号,氏名,部署,メールアドレス
12345,山田太郎,総務部,yamada@example.com
12346,鈴木花子,人事部,suzuki@example.com
...
| カラム |
必須 |
説明 |
| 社員番号 |
✅ |
ユーザーID兼パスワード |
| 氏名 |
✅ |
表示名 |
| 部署 |
❌ |
権限制御に使用 |
| メールアドレス |
❌ |
任意 |
4.2.2 エクスポート対象
- 本社社員のみ(関連会社1600名のうち280名程度)
- WordPressで調整済みの部署情報を使用
5. RAG側 実装要件
5.1 SSO連携
| 実装対象 |
ファイル |
| SSOトークン発行API |
app/api/routes/auth.py |
| Azure Functions ルーティング |
app/api/function_app.py |
| フロントエンド トークン受け取り |
app/web/src/context/authContext.tsx |
| CORS設定更新 |
app/api/function_app.py |
5.2 ユーザー管理拡張
| 実装対象 |
ファイル |
| 一括インポートAPI |
app/api/routes/admin.py |
| UserEntityに部署追加 |
app/api/services/table_storage.py |
| JWTに部署情報追加 |
app/api/services/auth.py |
5.3 環境設定
Azure Functions に以下の設定を追加:
| 設定キー |
説明 |
SSO_SHARED_SECRET |
WordPress共有シークレット |
SSO_TIMESTAMP_TOLERANCE |
タイムスタンプ許容秒数(デフォルト: 300) |
WORDPRESS_DOMAIN |
WordPressドメイン(CORS許可用) |
6. 部署権限制御仕様(P2)
6.1 権限チェックフロー
① ロールチェック
├─ admin / developer → 全文書アクセス可 ✓
└─ user → ②へ進む
② 部署チェック(userロールのみ)
├─ 文書の allowed_departments = ["*"] → アクセス可 ✓
├─ ユーザーの department ∈ allowed_departments → アクセス可 ✓
└─ それ以外 → 検索結果から除外 ✗
6.2 文書権限データ構造
{
"document_id": "doc-001",
"title": "人事評価マニュアル",
"allowed_departments": ["人事部", "総務部"]
}
| 値 |
意味 |
["*"] |
全員アクセス可(デフォルト) |
["部署A", "部署B"] |
指定部署のみアクセス可 |
[] |
admin/developerのみ |
6.3 既存文書の扱い
- 既存の全文書は
allowed_departments = ["*"] として扱う
- 管理画面から個別に権限を変更可能
7. セキュリティ要件
7.1 SSO連携
| 項目 |
対策 |
| 署名検証 |
HMAC-SHA256で改ざん防止 |
| リプレイ攻撃防止 |
タイムスタンプ有効期限5分 |
| トークン漏洩対策 |
URLパラメータは即座に削除、履歴に残さない |
| HTTPS必須 |
全通信をHTTPS化 |
7.2 シークレット管理
| 環境 |
管理方法 |
| 開発 |
環境変数または設定ファイル |
| 本番(WordPress) |
wp-config.php(.gitignore対象) |
| 本番(RAG) |
Azure Key Vault推奨 |
7.3 CORS設定
許可オリジン: https://wordpress.example.com
許可メソッド: POST, OPTIONS
許可ヘッダー: Content-Type, Authorization
8. 運用手順
8.1 月次ユーザー同期
1. WordPress管理画面から本社社員CSVをエクスポート
2. CSV→JSON変換スクリプトを実行
3. POST /api/manage/users/bulk でRAGにインポート
4. 結果を確認(created/updated/errors)
8.2 新規社員の追加
- 月次同期で自動的に追加される
- 即時対応が必要な場合は個別登録
8.3 退職者の対応
is_active: false に設定(論理削除)
- または月次同期から除外
9. 実装スケジュール
Phase 1(P1): SSO連携・ユーザー管理
| 担当 |
タスク |
見積もり |
| RAG |
SSOトークン発行API |
0.5日 |
| RAG |
ユーザーテーブル拡張(部署追加) |
0.5日 |
| RAG |
一括インポートAPI |
1日 |
| RAG |
フロントエンド SSOトークン受け取り |
0.5日 |
| RAG |
CSV変換スクリプト |
0.5日 |
| WordPress |
SSO連携機能(トークン取得・RAG起動) |
1日 |
| WordPress |
ユーザーCSVエクスポート機能 |
0.5日 |
| 共通 |
結合テスト |
1日 |
合計: 約5.5日
Phase 2(P2): 部署権限制御
| 担当 |
タスク |
見積もり |
| RAG |
検索フィルタリング実装 |
1日 |
| RAG |
文書権限管理API |
1日 |
| RAG |
管理画面UI |
2日 |
| 共通 |
テスト |
1日 |
合計: 約5日
10. 付録
10.1 エラーコード一覧
| コード |
HTTPステータス |
説明 |
INVALID_REQUEST |
400 |
リクエスト形式が不正 |
INVALID_SIGNATURE |
401 |
署名が一致しない |
EXPIRED_TIMESTAMP |
401 |
タイムスタンプ期限切れ |
USER_NOT_FOUND |
404 |
ユーザー未登録 |
UNAUTHORIZED |
401 |
認証トークンが無効 |
FORBIDDEN |
403 |
権限不足 |
10.2 ロール定義
| ロール |
説明 |
文書アクセス |
| admin |
管理者 |
全文書 |
| developer |
開発者 |
全文書 |
| user |
一般ユーザー |
部署制限あり |
10.3 連絡先
| 担当 |
連絡先 |
| RAG開発 |
(記入してください) |
| WordPress開発 |
(記入してください) |
更新履歴
| 日付 |
バージョン |
変更内容 |
| 2024-12-24 |
1.0 |
初版作成 |