📝

# 4.7 API 側の permission 実装パターン

に公開

これまで Django × Vue での認証・権限管理、JWT/セッション管理について解説してきた。
今回はその延長として、API 側での permission 実装パターン を紹介する。

SPA 構成では、フロントで「見せない制御」をしても、API を直接叩かれたら意味がない。
したがって API 側での認可チェック(二重防御) は必須になる。


1. DRF 標準の permission_classes

Django REST Framework には permission_classes という仕組みがあり、
API ごとに「このユーザーは実行できるか」を簡潔に記述できる。

代表的なのは以下のクラス。

  • AllowAny: 誰でもアクセス可
  • IsAuthenticated: ログイン済みユーザーのみ可
  • IsAdminUser: 管理者のみ可
  • DjangoModelPermissions: Django 標準の権限と連動

例:

from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView
from rest_framework.response import Response

class OrderListView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        # ログイン済みユーザーなら一覧を返す
        return Response({"orders": []})

2. 独自 Permission クラスの実装

実際の業務システムでは「モデル権限」だけでは足りない。
たとえば「営業部のユーザーは受注入力できるが、承認は部長以上」という要件。

その場合は独自の Permission クラスを定義する。

from rest_framework.permissions import BasePermission

class IsSalesDept(BasePermission):
    """営業部に所属しているかどうかを判定"""

    def has_permission(self, request, view):
        return any(dept.code.startswith("SALES") for dept in request.user.departments.all())

ビューで適用する:

class OrderCreateView(APIView):
    permission_classes = [IsAuthenticated, IsSalesDept]

    def post(self, request):
        # 営業部ユーザーのみ受注作成可能
        return Response({"status": "created"})

3. オブジェクト単位のチェック

さらに細かく「自分が作成したデータだけ編集可能」といった制御が必要なこともある。
その場合は has_object_permission を実装する。

class IsOwner(BasePermission):
    def has_object_permission(self, request, view, obj):
        return obj.created_by == request.user

ビューで使う例:

from rest_framework.generics import RetrieveUpdateAPIView
from .models import Order
from .serializers import OrderSerializer

class OrderDetailView(RetrieveUpdateAPIView):
    queryset = Order.objects.all()
    serializer_class = OrderSerializer
    permission_classes = [IsAuthenticated, IsOwner]

これで「自分が作った受注だけ更新可能」という制御ができる。


4. 実際の業務システムでの使い方

私の場合、Django 標準の Permission は使わず、
CustomUser / Dept / Role モデル をベースに自前の Permission を作っている。

例: 部長ロールだけ承認可能にする Permission

class CanApproveOrder(BasePermission):
    def has_permission(self, request, view):
        return request.user.userrole_set.filter(role__code="manager").exists()

さらに部署条件も絡めたい場合は、
Dept モデルや UserDept モデルを参照して判定する。


5. Vue 側との役割分担

  • Vue 側: メニュー表示制御(営業部なら営業メニューを表示)
  • API 側: 実際の処理権限チェック(営業部でも「承認」は不可)

この役割分担により、ユーザー体験とセキュリティを両立させている。


6. AI活用のポイント

Permission 実装に関しても AI は有効だが、注意点がある。

  • 得意なところ

    • 標準の permission_classes や独自クラスの雛形生成
    • IsAuthenticatedhas_object_permission を組み合わせた基本パターンの提示
  • 苦手なところ

    • プロジェクト固有の権限モデル(CustomUser / Dept / Role など)を前提にした実装
    • 実際の業務要件に即したロジック(「営業部長は承認可能だが課長は不可」など)
  • よくあるズレの例

    • AI のコードでは request.user.departments を直接参照しているが、実際のモデルでは UserDept を経由しないと取得できない
    • AI は「この属性があるはず」と前提して書くが、プロジェクトの実装とは異なるため動かない

👉 つまり AIは雛形まで、実際の権限ロジックは人間が業務知識を前提に肉付けする、という割り切りが必要。


まとめ

  • DRF では permission_classes で API ごとに認可制御を設定できる
  • 業務システムでは独自 Permission クラスを作って要件に対応する
  • has_permission(全体チェック)と has_object_permission(個別オブジェクトチェック)の両方を使い分ける
  • フロント(Vue)では UI 制御、API 側では厳格な認可チェック、という二重防御が必須
  • AI は雛形生成に有効だが、実際の業務権限ロジックは業務知識を持つ人間が組み込む必要がある

次回からはフロントエンド編に進み、Vue 3 による UI/UX 改善 を掘り下げていく予定。

Discussion