コンテンツにスキップ

リソースレベル権限システム

リソースレベル権限システムにより、ユーザーはプロジェクトや企画ごとに細かい粒度の権限を持つことができます。

概要

なぜリソースレベル権限が必要か?

従来のグローバルロールシステムでは: - ユーザーはシステム全体で1つのロールしか持てない - 特定のプロジェクトだけで管理者になることができない - 権限が粗く、細かい制御ができない

リソースレベル権限システムでは: - ✅ プロジェクトAでは管理者、プロジェクトBでは閲覧者 - ✅ 企画Xでは編集可能、企画Yでは読み取りのみ - ✅ 9種類の細かい権限で柔軟に制御 - ✅ 期限付き権限で一時的なアクセスを許可

リソースタイプ

PROJECT

イベント全体を表すリソース(例: 千葉大祭2024)

用途: - イベント全体の管理者を設定 - 企画承認権限の付与 - リソース割り当て権限の付与

CIRCLE_PROJECT

個別の企画を表すリソース(例: 特定サークルの出店企画)

用途: - 企画のマネージャー・メンバー設定 - 企画情報の編集権限 - チェックイン権限

権限の種類 (9種類)

権限 説明 用途例
READ リソースの閲覧 企画情報の確認
WRITE リソースの編集・更新 企画名・説明の変更
DELETE リソースの削除 企画のアーカイブ
MANAGE_MEMBERS メンバーの追加・削除 企画メンバーの管理
MANAGE_PERMISSIONS 権限の付与・削除 他のユーザーに権限を与える
APPROVE 申請の承認 企画申請の承認・却下
CHECKIN チェックイン操作 説明会の出席確認
ALLOCATE_RESOURCES リソースの割り当て テント・予算の配分
VIEW_PRIVATE 非公開情報の閲覧 内部メモの閲覧

ロールテンプレート

よく使う権限セットをテンプレートとして保存できます。

Project用ロールテンプレート

ProjectAdmin (全権限)

すべての操作が可能です。

["READ", "WRITE", "DELETE", "MANAGE_MEMBERS", "MANAGE_PERMISSIONS",
 "APPROVE", "ALLOCATE_RESOURCES", "VIEW_PRIVATE"]

ProjectManager (管理権限)

承認とリソース割り当てが可能です。

["READ", "WRITE", "APPROVE", "ALLOCATE_RESOURCES", "VIEW_PRIVATE"]

ProjectEditor (編集権限)

閲覧と編集が可能です。

["READ", "WRITE", "VIEW_PRIVATE"]

ProjectViewer (閲覧のみ)

閲覧のみ可能です。

["READ"]

CircleProject用ロールテンプレート

Manager (企画管理者)

企画の全操作が可能です。

["READ", "WRITE", "DELETE", "MANAGE_MEMBERS", "MANAGE_PERMISSIONS",
 "CHECKIN", "VIEW_PRIVATE"]

Editor (企画編集者)

編集とチェックインが可能です。

["READ", "WRITE", "CHECKIN", "VIEW_PRIVATE"]

Member (一般メンバー)

閲覧とチェックインが可能です。

["READ", "CHECKIN"]

Viewer (閲覧のみ)

閲覧のみ可能です。

["READ"]

使用例

例1: プロジェクト管理者を追加

ユーザーAを「千葉大祭2024」の管理者にする:

curl -X POST /api/resource-permissions \
  -d '{
    "userId": "user-a-uuid",
    "resourceType": "PROJECT",
    "resourceId": "chibafes2024",
    "roleTemplate": "ProjectManager"
  }'

例2: 企画メンバーに編集権限を付与

ユーザーBを特定企画の編集者にする:

curl -X POST /api/resource-permissions \
  -d '{
    "userId": "user-b-uuid",
    "resourceType": "CIRCLE_PROJECT",
    "resourceId": "circle-project-123",
    "roleTemplate": "Editor"
  }'

例3: 期限付き権限の付与

ユーザーCに1ヶ月間の編集権限を付与:

curl -X POST /api/resource-permissions \
  -d '{
    "userId": "user-c-uuid",
    "resourceType": "CIRCLE_PROJECT",
    "resourceId": "circle-project-456",
    "permissions": ["READ", "WRITE"],
    "expiresAt": "2025-12-31T23:59:59Z"
  }'

例4: カスタム権限セット

特定の権限のみを付与:

curl -X POST /api/resource-permissions \
  -d '{
    "userId": "user-d-uuid",
    "resourceType": "PROJECT",
    "resourceId": "chibafes2024",
    "permissions": ["READ", "APPROVE", "VIEW_PRIVATE"]
  }'

実装方法

エンドポイントでの使用

import { requireResourcePermission } from '@/lib/api/auth';

// 企画の更新エンドポイント(WRITE権限が必要)
app.put('/circle-project/:id',
  requireResourcePermission('CIRCLE_PROJECT', 'id', ['WRITE']),
  async (c) => {
    // 権限チェック済み
    const id = c.req.param('id');
    // ...更新処理
  }
);

プログラムからの権限チェック

import { hasResourcePermission } from '@/lib/api/auth';

const canEdit = await hasResourcePermission(
  userId,
  'CIRCLE_PROJECT',
  projectId,
  ['WRITE']
);

if (canEdit) {
  // 編集処理
}

フロントエンドでの使用

import { useResourcePermission } from '@/hooks/useResourcePermission';

function ProjectActions({ projectId }) {
  const { hasPermission: canEdit } = useResourcePermission(
    'CIRCLE_PROJECT',
    projectId,
    ['WRITE']
  );

  return (
    <div>
      {canEdit && <button>編集</button>}
    </div>
  );
}

後方互換性

FullAccessAdminロールを持つユーザーは、すべてのリソースに対して全権限を自動的に持ちます。

// FullAccessAdminの場合、権限チェックは常にtrueを返す
if (user.role === 'FullAccessAdmin') {
  return true;
}

ベストプラクティス

1. 最小権限の原則

必要最小限の権限のみを付与します。

悪い例:

// すべての権限を付与
permissions: ["READ", "WRITE", "DELETE", "MANAGE_MEMBERS",
              "MANAGE_PERMISSIONS", "APPROVE", ...]

良い例:

// 必要な権限のみ
permissions: ["READ", "WRITE"]

2. ロールテンプレートの活用

カスタム権限セットより標準テンプレートを優先します。

悪い例:

// 毎回カスタム権限を指定
permissions: ["READ", "WRITE", "CHECKIN", "VIEW_PRIVATE"]

良い例:

// ロールテンプレートを使用
roleTemplate: "Editor"

3. 期限の設定

一時的な権限には必ず有効期限を設定します。

悪い例:

// 期限なし
expiresAt: null

良い例:

// 30日間の期限
expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000)

4. 監査ログ

権限の付与・変更・削除は記録されます。

{
  userId: "user-uuid",
  grantedBy: "admin-uuid",
  grantedAt: "2024-01-01T00:00:00Z",
  permissions: ["READ", "WRITE"]
}

トラブルシューティング

問題: 権限チェックが常にfalseを返す

原因: 1. リソースIDが間違っている 2. ResourcePermissionテーブルにデータが存在しない 3. 権限の有効期限が切れている

解決策:

# 権限チェックエンドポイントでデバッグ
curl "/api/resource-permissions/check?\
resourceType=CIRCLE_PROJECT&\
resourceId=YOUR_PROJECT_ID&\
permissions=READ,WRITE"

問題: FullAccessAdminなのにアクセスできない

原因: 新しい権限チェックロジックが正しく実装されていない

解決策: hasResourcePermission関数でFullAccessAdminの特別扱いを確認

// lib/api/auth.ts
if (user?.role === 'FullAccessAdmin') {
  return true; // これが実行されているか確認
}

詳細情報


最終更新: 2026-01-07