認可方式はコードを置く場所だけでは決められません。権限粒度、並行数、一貫性、可用性、運用の複雑さを合わせて考えます。

まず概念を分けます。

  • 認証:アクセスする人が誰かを確認する。
  • トークン検証:署名、発行者、対象、期限を検証する。
  • 認可判断:その人に操作を許可できるか決める。
  • 権限の適用:判断を API、リソース、データへ反映する。

Spring Authorization Server は Spring Security を基盤とする OAuth 2.0・OpenID Connect の認可サーバー実装です。認可フローとアクセス・リフレッシュトークンの発行を扱い、ユーザー認証と連携できますが、リソース認可サービスそのものではありません。

「判断する場所」と「検査を適用する場所」から三つの方式を整理できます。互いに排他的ではなく、組み合わせられます。

1. ゲートウェイでの入口検査

ルールが比較的単純な場合に向く方式です。一般に次を担当します。

  1. Access Token の検証。JWT なら署名、発行者、対象、有効期限を確認。
  2. 業務上必要なら失効やアカウント状態を確認。
  3. ルート、役割、Scope による基本的なアクセス制御。
  4. 許可・拒否リスト、レート制限などの入口方針。

有効なトークンと利用可能な API が主な条件なら、多くの検査を担えます。サービスが信頼できるゲートウェイからしかアクセスできず、転送された本人情報も検証できるなら結果を再利用できます。他の入口がある場合は独立した認証・認可が必要です。

早期拒否、サービス側コードの削減、入口ルールの集中管理、内部への無効トラフィック削減が利点です。

粒度が細かくなると、ユーザー、役割、組織、リソース、データ権限の照会が増えます。毎回 DB や集中サービスへ問い合わせる構成では、この経路がボトルネックになります。

ゲートウェイのクラスター化は CPU、接続数、スループットを改善しますが、権限照会の問題を自動で解消しません。ポリシーのキャッシュ、ローカルトークン検証、照会の一括化、事前ロード、タイムアウト、障害方針、認可サービスの高可用性も必要です。

すべての認可を入口へ集める必要はなく、複雑なデータ権限は業務側で追加判断します。

2. 集中型の認可判断

独立した権限サービスやポリシーエンジンがルールを管理し、主体、リソース、操作、文脈を受け取って許可・拒否を返します。呼び出し元が結果を適用します。

クライアント → ゲートウェイまたは業務サービス
    → 権限サービス・ポリシーエンジン
    → 許可または拒否 → 呼び出し元が適用

ルールの集中保守、RBAC・ABAC の共通実装、サービス間のモデル統一、ルール変更時の個別改修削減が利点です。

一方、ネットワーク往復、障害時の広い影響、集中負荷、キャッシュ失効と一貫性の問題が増えます。

キャッシュ、タイムアウト、サーキットブレーカー、高可用性を設計し、有効な判断が得られない保護対象操作は原則拒否します。キャッシュ再利用を認めるなら、対象操作、有効期間、失効が反映されるまでの時間を定めます。

即時反映が必要な変更では TTL を短くするだけでは不十分です。同期照会や期限内の確実な無効化が必要です。短い遅延を許容する権限なら長めのローカルキャッシュを選べます。

集中管理でも毎回リモート判断する必要はありません。ポリシーを各サービスへ配布し、多くをローカル評価、特殊な場合だけ中心へ照会する構成も可能です。

3. サービス内認可とポリシー同期

業務操作、所有関係、行単位まで権限が及ぶと、入口だけでは足りません。Controller、Service、メソッドセキュリティなどで検査します。

@PreAuthorize("@permission.canAccess(authentication, #orderId)")
public OrderDetail getOrderDetail(Long orderId) {
    return orderService.getDetail(orderId);
}

要求はゲートウェイを通りますが、具体的な許可判断には対象サービスの業務データを使います。

データに近い判断、所有者・操作単位の権限、業務負荷に応じた分散、ゲートウェイの責務整理が利点です。ただし、入口検査がなければ無効要求が内部へ届き、各サービスへの実装、ルール差異、配布・モデル更新、Controller を迂回する経路への対処が必要になります。

基本原則は次のとおりです。

  • 明示的な許可がなければ拒否する。
  • 特定の Controller 切り口だけでなく全入口を保護する。
  • サービス間でも呼び出し元を認証し、操作を認可する。
  • クライアントからのパラメーターだけを信頼しない。
  • キャッシュの期限と失効を設ける。
  • 更新を各インスタンスへ適時に同期する。

設定を DB や設定サービスに集約し、発行・購読でローカルキャッシュを更新できます。これは「集中ポリシー保存と分散キャッシュ同期」と呼ぶほうが正確で、黒板アーキテクチャと無理に分類する必要はありません。

4. 三方式の比較

方式 判断・適用場所 利点 主な代償
入口検査 ゲートウェイ 早期拒否、ルール集中、改修少 負荷集中、業務文脈の不足
集中判断 権限サービスが判断し呼び出し元が適用 モデル統一、複雑な方針 ネットワーク依存、集中ボトルネック
ローカル認可 業務サービス 業務データに近く細粒度 一貫性、検査の網羅性

実際には組み合わせが一般的です。

要求 → ゲートウェイ:トークンとルート権限
    → 業務サービス:リソース・データ・操作権限
        ├── ローカルポリシーと業務データ
        └── 必要なら集中判断
    → 許可後に業務実行

例えば入口で無効トークンや Scope 不足を拒否し、サービスで特定の注文、口座、組織データを使えるか確認します。

5. 判断すべき品質属性

少なくとも次に影響します。

  1. 遅延:追加のリモート照会。
  2. スループット:負荷の集中場所と分散。
  3. 可用性:認可サービス障害時の安全な動作。
  4. 一貫性:変更が全ノードへ届く時間。
  5. 安全性:迂回、本人情報の偽造、古い権限。
  6. 拡張性:役割、リソース、データ粒度への対応。
  7. 運用:配布、失効、調査の複雑さ。
  8. 通信・費用:無効な内部要求と検査のコスト。

細粒度だからすべてをサービスへ、高負荷だからすべてを入口へ、とは決められません。

共通で低コストの入口検査、業務データに依存するサービス内判断、集中ポリシー管理、ローカルキャッシュ、イベント同期を組み合わせ、一貫性の要求に応じて失効を設計します。

必要な粒度、スループット、可用性、変更反映の許容時間を明確にして初めて、どこで判断し、どこで適用し、どの複雑さを引き受けるかを決められます。