React 操作できるかをAPIから返して権限の分岐を減らす
編集ボタンを出すために、画面ごとに「管理者か」「所有者か」を判定していることがあります。
後から「担当者も編集できる」「停止中は管理者でも編集できない」といった条件が加わると、複数の画面を同時に直す必要が出てきます。
今回は、役割の名前を画面で判定する代わりに、その対象に対して何ができるかをAPIから返す構成を紹介します。
ロール名と操作の可否は同じではない
adminやmemberのような役割をロールと呼びます。同じロールでも、所属する組織や操作対象の状態によって、できることが変わる場合があります。
編集できる条件の例組織に所属している
かつ、編集権限を持っている
かつ、対象が停止されていないこの条件を各画面に複製すると、サーバー側のルールが変わったときに、古い判定が残りやすくなります。
サーバーで判定した結果をcanEditなどの名前で返せば、画面は表示に必要な結果を利用できます。
操作可否を対象のデータに含める
ProjectDetail.tsexport type ProjectDetail = {
id: string;
name: string;
allowedActions: {
canEdit: boolean;
canDelete: boolean;
};
};allowedActionsは、その対象について表示上どの操作を案内できるかをまとめた項目です。
利用者全体に1つのcanEditを持たせるのではなく、どのプロジェクトや組織に対する判定なのかを明確にします。同じ利用者でも、対象によって結果は変わり得ます。
画面では結果を使ってボタンを出す
ProjectActions.tsximport type { ProjectDetail } from './ProjectDetail';
type Props = {
project: ProjectDetail;
isSaving: boolean;
onEdit: () => void;
};
export const ProjectActions = ({ project, isSaving, onEdit }: Props) => (
<div>
{project.allowedActions.canEdit && (
<button type="button" disabled={isSaving} onClick={onEdit}>
編集
</button>
)}
</div>
);権限による出し分けと、保存中の二重操作を防ぐ表示を分けています。canEditは操作権限、isSavingは画面の現在の処理状態です。
この例は、データ取得が成功した後に表示する部品です。取得中や失敗時の表示は、親の画面で扱います。
ボタンを隠すか、理由を表示して無効にするかは画面の目的によります。たとえば「担当者へ権限を依頼できる」と案内したいなら、理由付きの表示が役立つこともあります。
取得失敗を権限なしと混同しない
データがまだない場合に、次のように操作を有効にしないこと自体は大切です。
操作を有効にしない初期値const canEdit = project?.allowedActions.canEdit ?? false;ここでのprojectは、未取得ならundefinedになる取得結果です。
ただし、通信エラーまで「あなたには権限がありません」と表示すると、利用者は何をすればよいかわかりません。
| 状態 | 表示の例 |
|---|---|
| 取得中 | 読み込み中。操作は有効にしない |
| 通信失敗 | 取得エラーと再試行の案内 |
| 取得成功・操作不可 | 閲覧用の表示、必要なら権限の説明 |
| 取得成功・操作可能 | 編集ボタンを表示 |
falseの初期値を使うことと、エラーの原因を同じに扱うことは別です。
更新APIは現在の権限を改めて確認する
画面へ返したcanEditは、取得した時点の結果です。画面を開いた後に権限が取り消される場合もあります。
また、ブラウザー上の値やボタンの表示は変更できます。更新APIへcanEdit: trueを送り、それを信用して許可する設計にはしません。
更新APIでは、認証済みの利用者と操作対象を使い、現在の権限を確認します。対象の情報に基づく認可については、Microsoft Learnのリソースベース認可の説明も参照してください。
表示と更新の役割取得API:利用者と対象から操作可否を計算し、画面へ返す
画面:返された結果で操作を案内する
更新API:現在の権限と対象の状態を確認して実行する取得API自体も、そのデータを閲覧してよいかを確認してから返します。操作可否を含めることは、閲覧権限の検証を不要にするものではありません。
判定ルールをサーバーでも二重管理しない
表示用のcanEditと、更新時の認可で別々に同じ条件を書くと、サーバー内でもずれる可能性があります。
共通の認可処理やポリシーを呼べるようにし、表示時も更新時も、その時点の利用者と対象を渡す方法があります。
ただし、判定に必要な情報の取得量にも注意します。一覧の各行で何度もDBへ問い合わせるなら、まとめて必要な情報を取得する設計を検討します。画面の分岐を減らした代わりに、一覧取得が極端に重くならないようにします。
小さな画面に必ず必要な構成ではない
管理者だけが使う単純な画面なら、ロール判定の方がわかりやすい場合もあります。
対象ごとの権限や状態の組み合わせが増え、複数画面で同じ複雑な分岐を書いているときに、操作単位の結果を返す方法が役立ちます。
導入後は、別の組織へ切り替えたときやログアウト時に、古い操作可否のキャッシュを使い続けないことも確認します。
ボタンの表示を決める処理を減らしつつ、実行の許可はサーバーで確認する。この分担を保つことが、権限変更に追従しやすい画面を作るポイントです。