RESTful API データモデリング

RESTful APIで権限管理を実現するデータモデリング:ロールとパーミッションの設計

Tags: RESTful API, データモデリング, 権限管理, 認可, RBAC

はじめに

RESTful APIは、様々なアプリケーションやサービス間でのデータ連携の基盤となっています。APIを設計する上で、データの構造やエンドポイントをどのように定義するかといった「データモデリング」は非常に重要な要素です。そして、多くのAPIにおいて、どのユーザーがどのリソースに対してどのような操作を行えるか、すなわち「権限管理(認可)」の機能は不可欠です。

しかし、この権限管理のデータモデリングは、要件によって複雑性が増しやすく、設計に悩むポイントの一つでもあります。特に、アプリケーションの機能が増えたり、ユーザーの種類が多様化したりするにつれて、柔軟性と保守性のバランスを取りながら設計を進める必要があります。

この記事では、RESTful APIにおける権限管理を実現するためのデータモデリングに焦点を当て、基本的な考え方から具体的な設計パターンまでを解説します。特に、多くのシステムで採用されているロールベースアクセス制御(RBAC)を中心に、データモデルをどのようにRESTfulなリソースとして表現し、APIとして設計していくかを見ていきます。

RESTful APIにおける権限管理の基本

まず、権限管理を考える上で重要な二つの概念、「認証 (Authentication)」と「認可 (Authorization)」を明確にしておきましょう。

RESTful API設計におけるデータモデリングは、主にこの「認可」の部分に関連します。つまり、「誰が(主体)」、「どのリソースに対して」、「何ができるか(操作)」という関係性をデータとしてどのように表現し、APIとして提供するかを設計することになります。

権限管理のモデルにはいくつか種類がありますが、広く用いられているのがロールベースアクセス制御(RBAC:Role-Based Access Control)です。

ロールベースアクセス制御 (RBAC) の基本要素

RBACでは、権限を個々のユーザーに直接付与するのではなく、「ロール(役割)」を介して付与します。基本的な要素は以下の通りです。

  1. 主体 (Subject): アクセスを行う主体。通常はユーザーですが、アプリケーションやサービスアカウントなども該当し得ます。
  2. ロール (Role): 主体に付与される役割。例:「管理者 (Admin)」「編集者 (Editor)」「一般ユーザー (User)」。ロールは複数の主体が共有できます。
  3. パーミッション (Permission): 特定のリソースに対する特定の操作を許可する権利。例:「ユーザー情報を参照する」「記事を編集する」「設定を変更する」。
  4. リソース (Resource): アクセス制御の対象となるオブジェクト。例:「ユーザー情報」「記事データ」「設定情報」。

RBACの考え方はシンプルです。「主体」に「ロール」を割り当て、「ロール」に「パーミッション」を割り当てることで、主体は割り当てられたロールが持つパーミッションを行使できるようになります。

このRBACモデルをRESTful APIのデータモデリングに落とし込むことを考えましょう。

RBACモデルのリソース設計

RBACの各要素(主体、ロール、パーミッション)をRESTfulなリソースとしてどのように表現できるか、典型的な例を見ていきます。主体がユーザーである場合を想定します。

1. ユーザーリソース (/users)

ユーザー自身を表現するリソースです。ユーザーに紐づく情報として、ユーザー名、プロフィールなどと共に、そのユーザーに付与されている「ロール」への関連性を持たせます。

例:ユーザーリソースの表現

{
  "id": "user123",
  "username": "kenta.sato",
  "name": "佐藤 健太",
  "email": "kenta.sato@example.com",
  // その他のユーザー属性...
  "links": [
    { "rel": "self", "href": "/users/user123" },
    { "rel": "roles", "href": "/users/user123/roles" } // このユーザーに紐づくロールへのリンク
  ]
}

ユーザー一覧の取得には GET /users、個別のユーザー取得には GET /users/{userId} といったエンドポイントが考えられます。上記の例では、そのユーザーが持つロールの一覧を取得するためのエンドポイント /users/{userId}/roles へのリンクを含めています。HATEOASの原則に則り、関連リソースへのリンクを含めることで、APIの discoverability を高めることができます。

2. ロールリソース (/roles)

システム内に存在する役割を表現するリソースです。ロール名、説明などを持つことができます。ロールに紐づく情報として、そのロールが持つ「パーミッション」への関連性を持たせます。

例:ロールリソースの表現

{
  "id": "admin",
  "name": "管理者",
  "description": "システム全体の管理権限を持つロール",
  "links": [
    { "rel": "self", "href": "/roles/admin" },
    { "rel": "permissions", "href": "/roles/admin/permissions" } // このロールに紐づくパーミッションへのリンク
  ]
}

ロール一覧の取得には GET /roles、個別のロール取得には GET /roles/{roleId} といったエンドポイントが考えられます。上記の例では、そのロールが持つパーミッションの一覧を取得するためのエンドポイント /roles/{roleId}/permissions へのリンクを含めています。

3. パーミッションリソース (/permissions)

システム内で許可される具体的な操作を表現するリソースです。パーミッション名、説明などを持つことができます。多くの場合、「リソースタイプ:操作」のような命名規則を用いると分かりやすくなります(例:user:read, article:write, settings:update)。

例:パーミッションリソースの表現

{
  "id": "user:read",
  "name": "ユーザー情報参照",
  "description": "システム内のユーザー情報を参照できる権限"
}

パーミッション一覧の取得には GET /permissions、個別のパーミッション取得には GET /permissions/{permissionId} といったエンドポイントが考えられます。パーミッションはロールに紐づくことで効果を発揮するため、単独で操作されることは少ないかもしれませんが、システムに存在するパーミッションを一覧表示したり、定義を確認したりする際に有用です。

リソース間の関連性のモデリング

RBACモデルにおける重要な関連性は以下の2つです。

  1. ユーザー ↔ ロール
  2. ロール ↔ パーミッション

これらの関連性をAPIとしてどのように表現するかを考えます。

ユーザーとロールの関連性

あるユーザーがどのロールを持っているか、また、あるロールにどのユーザーが属しているか、といった関連性を表現します。これは、ユーザーリソースの子リソースとしてロールを持たせるか、あるいは関連リソースへのリンクや別の専用リソースで表現するなどの方法があります。RESTfulの原則に従い、関連性を別々のリソースとして扱い、リンクで繋ぐ方法が一般的です。

例:ユーザーに紐づくロール一覧のエンドポイント

GET /users/{userId}/roles

[
  {
    "id": "admin",
    "name": "管理者",
    "links": [
      { "rel": "self", "href": "/roles/admin" } // 個別ロールリソースへのリンク
    ]
  },
  {
    "id": "editor",
    "name": "編集者",
     "links": [
      { "rel": "self", "href": "/roles/editor" }
    ]
  }
  // ... 他のロール
]

このエンドポイントでは、指定されたユーザーに現在付与されているロールのリストを返します。ロールの詳細が必要な場合は、各要素に含まれるリンクをたどることで取得できます。

例:ユーザーへのロール付与・剥奪エンドポイント

ロールとパーミッションの関連性

あるロールがどのパーミッションを持っているか、また、あるパーミッションがどのロールに紐づいているか、といった関連性を表現します。これも、ロールリソースの子リソースとしてパーミッションを持たせるか、あるいは関連リソースへのリンクで表現します。

例:ロールに紐づくパーミッション一覧のエンドポイント

GET /roles/{roleId}/permissions

[
  {
    "id": "user:read",
    "name": "ユーザー情報参照",
    "links": [
      { "rel": "self", "href": "/permissions/user:read" } // 個別パーミッションリソースへのリンク
    ]
  },
  {
    "id": "article:write",
    "name": "記事作成・編集",
    "links": [
      { "rel": "self", "href": "/permissions/article:write" }
    ]
  }
  // ... 他のパーミッション
]

このエンドポイントは、指定されたロールに付与されているパーミッションのリストを返します。パーミッションの詳細が必要な場合は、各要素に含まれるリンクをたどることで取得できます。

例:ロールへのパーミッション付与・剥奪エンドポイント

ユーザーの最終的なパーミッション一覧の取得

認可判断を行う際に、「このユーザーは〇〇のパーミッションを持っているか?」という情報が必要になります。RBACモデルでは、ユーザーに付与されたすべてのロールが持つパーミッションを合算したものが、そのユーザーの最終的なパーミッションセットとなります。

この情報を取得するためのエンドポイントを設けることも有用です。

例:ユーザーの有効なパーミッション一覧のエンドポイント

GET /users/{userId}/permissions

[
  {
    "id": "user:read",
    "name": "ユーザー情報参照"
  },
  {
    "id": "article:write",
    "name": "記事作成・編集"
  },
  {
    "id": "settings:read",
    "name": "設定参照"
  }
  // ... ユーザーが持つすべてのロールから集計されたパーミッション
]

このエンドポイントは、指定されたユーザーが持つすべてのロールをたどり、それらのロールに紐づくパーミッションを重複なく集計したリストを返します。これは、ユーザーインターフェースでユーザーに許可されている操作を表示したり、クライアント側で特定の操作ボタンの表示/非表示を制御したりする際に役立ちます。ただし、実際の認可判断は、原則としてAPIを受け付けたサーバーサイドで行うべきです。

設計における考慮事項と実践的ヒント

権限管理のデータモデリングとAPI設計を行う際には、以下のような点を考慮するとより堅牢で保守しやすい設計になります。

避けるべきアンチパターン

権限管理のデータモデリングにおいて、避けるべき典型的なアンチパターンをいくつか紹介します。

まとめ

RESTful APIにおける権限管理のデータモデリングは、APIのセキュリティと保守性を確保するために非常に重要です。特にロールベースアクセス制御(RBAC)は、多くのシステムで採用されており、ユーザー、ロール、パーミッションという基本的な要素をリソースとして適切にモデリングし、それらの関連性をRESTfulな手法(URI、リンクなど)で表現することで、理解しやすく管理しやすいAPIを設計することができます。

この記事で解説したように、ユーザー、ロール、パーミッションをそれぞれ独立したリソースとして定義し、ユーザーとロール、ロールとパーミッションの関連性を子リソースやリンクとして表現する方法は、RBACモデルをRESTful APIに適用する際の強力な基盤となります。

設計においては、リソースの粒度とパーミッションの定義のバランス、柔軟性とシンプルさのトレードオフ、そしてパフォーマンスやセキュリティといった実践的な観点を考慮することが不可欠です。アンチパターンを避け、これらの要素を慎重に検討することで、変化に強く、安心して利用できる権限管理APIを実現できるでしょう。

権限管理はシステム開発において避けて通れない課題です。データモデリングの段階から、明確で一貫性のある設計を心がけることが、長期的な成功に繋がります。