タラバガニー設計局stalins.clubNOTE/notes/path-hierarchy-can-model-authorization-hierarchy

パス階層を認可階層として使う

REST 風の URL がドメインの包含関係に沿っているなら、パスのネストをそのまま認可の絞り込みとして使える。

たとえば次のような API を考える。

/projects/{project}
/projects/{project}/tasks/{task}
/projects/{project}/tasks/{task}/assignees

{project} の時点で「この project を閲覧できる」、さらに {task} で「この project 配下の task である」、更新系の枝では「この task を編集できる」という条件を一度ずつ解決できれば、下位ハンドラで同じ取得・認可を繰り返さずに済む。

tanukirpc の RouteWithTransformer はこの構造を型にも反映できる。外側の Router[App]/projects/{id}Router[ProjectScope] に、さらに下で Router[TaskScope]Router[OwnerScope] に変換できるため、ルート木と認可済みコンテキストの木が一致する認可済みリソースをハンドラ入力にすると前提を構造化できる の「認可済み値を入力にする」を、ルーティング階層へ広げた形である。

Laravel の route group も middleware を親から子へ継承できるので、認証や粗い権限の共有には近い。ただし Route Model Binding と Policy は別の仕組みで、子グループに入ったから controller のモデル型自体が OwnerPost のように変わるわけではない。tanukirpc の特徴は、ルート階層の変化と Registry の型変化を同じ操作で表せる点にある。

この方式がきれいに働く条件は、URL 階層と権限境界が概ね一致していることである。たとえば同じ /documents/{id} でも vieweditapprove が別々のロールで、パスを分けたくない場合、認可階層を無理に URL 階層へ押し込むとルーティングが権限モデルに引きずられる。その場合は 認可をルーティングではなくメソッド境界に置く のように操作境界へ認可を置く方が自然になる。

出典

▸ ノート一覧に戻る