🦁

# 4.8 Django 設定(CORS と認証まとめ)

に公開

ここまでで API 設計の基礎を見てきた。
今回は Vue 側から安全に API を叩けるようにするために、Django 側の CORS 設定ログイン処理 を整備する。

👉 この記事は これまでの認証・権限管理のまとめ という位置づけであり、AI 活用の話は登場しない。
基本的な構成を押さえつつ、「実際の業務システムではこう組み合わせている」という整理を目的としている。


1. CORS 設定

Vue(Vite dev server)と Django API は別オリジンで動くため、CORS を許可しないとブラウザが通信をブロックしてしまう。

# settings.py

INSTALLED_APPS = [
    ...,
    "corsheaders",
]

MIDDLEWARE = [
    "corsheaders.middleware.CorsMiddleware",
    "django.middleware.common.CommonMiddleware",
    ...
]

CORS_ALLOW_CREDENTIALS = True
CORS_ALLOWED_ORIGINS = [
    "http://localhost:5173",  # 開発環境(Vue)
    "https://example.com",    # 本番
]

👉 これで Vue 側の axios から withCredentials: true を付けたリクエストが通るようになる。


💡 CORSってなに?

CORS(Cross-Origin Resource Sharing:クロスオリジンリソースシェアリング)とは、
異なるオリジン(スキーム・ホスト・ポートの組み合わせ)間での通信をブラウザが制御する仕組み のこと。

例:

  • Vue (Vite) の開発サーバー → http://localhost:5173
  • Django API サーバー → http://localhost:8000

ポート番号が異なるため、両者は「別オリジン」と見なされ、デフォルトでは通信不可。
サーバー側で CORS_ALLOWED_ORIGINS を設定することで「このオリジンからのアクセスは許可」と宣言し、通信が通るようになる。


2. DRF の認証設定

業務システムでは「ログインしていないと API を使えない」ようにするのが基本。

# settings.py

REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": [
        "rest_framework.authentication.SessionAuthentication",  # セッション認証
        # "rest_framework_simplejwt.authentication.JWTAuthentication",  # JWT 認証(外部公開用)
    ],
    "DEFAULT_PERMISSION_CLASSES": [
        "rest_framework.permissions.IsAuthenticated",
    ],
}

認証方式の使い分け

  • SessionAuthentication

    • Django 標準
    • Cookie を使ってログイン状態を維持
    • 社内システムやイントラ環境に最適
  • JWTAuthentication

    • JSON Web Token を使った stateless 認証
    • モバイルアプリや外部向け API に向いている
    • 有効期限・リフレッシュ制御が必要

👉 多くの業務システムでは「社内用はセッション認証」「外部向けAPIはJWT」というハイブリッド構成が使われる。


3. ログイン API の実装(DRF 流)

Serializer

# serializers.py
from rest_framework import serializers

class LoginSerializer(serializers.Serializer):
    username = serializers.CharField()
    password = serializers.CharField()

View

# views.py
from django.contrib.auth import authenticate, login, logout
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .serializers import LoginSerializer

class LoginView(APIView):
    def post(self, request):
        serializer = LoginSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = authenticate(
            request,
            username=serializer.validated_data["username"],
            password=serializer.validated_data["password"],
        )
        if user is not None:
            login(request, user)
            return Response({"message": "ログイン成功"})
        return Response({"error": "認証失敗"}, status=status.HTTP_401_UNAUTHORIZED)


class LogoutView(APIView):
    def post(self, request):
        logout(request)
        return Response({"message": "ログアウトしました"})


class AuthStatusView(APIView):
    def get(self, request):
        if request.user.is_authenticated:
            departments = [
                {"code": d.code, "name": d.name}
                for d in request.user.userdept_set.all()
            ]
            roles = [r.code for r in request.user.roles.all()]
            return Response({
                "username": request.user.username,
                "full_name": request.user.get_full_name(),
                "is_staff": request.user.is_staff,
                "departments": departments,
                "roles": roles,
            })
        return Response({"authenticated": False}, status=status.HTTP_401_UNAUTHORIZED)

URL

# urls.py
from django.urls import path
from .views import LoginView, LogoutView, AuthStatusView

urlpatterns = [
    path("auth/login/", LoginView.as_view(), name="login"),
    path("auth/logout/", LogoutView.as_view(), name="logout"),
    path("auth/status/", AuthStatusView.as_view(), name="auth_status"),
]

4. 部署とロールを返す意味

業務システムでは 「誰がどの部署に所属し、どのロールを持っているか」 が必ず必要になる。

例:

{
  "username": "taro",
  "full_name": "山田 太郎",
  "is_staff": true,
  "departments": [
    { "code": "A001", "name": "営業一課" },
    { "code": "A002", "name": "営業二課" }
  ],
  "roles": ["order_approve", "asset_manager"]
}
  • 部署(departments):兼務に対応できる
  • ロール(roles):メニューやボタン制御に利用できる

👉 /auth/status/ を拡張しておけば、Vue 側の制御がシンプルになる。


5. Vue 側との噛み合わせ

  • axios 側で withCredentials: true を付与
  • Django 側で CORS_ALLOW_CREDENTIALS = True を設定
  • Vue のストア(Pinia)で /auth/status/ を呼び出して保持

👉 認証・権限の基本フローがこれで完成する。


6. 統合認証(Okta / Google)

企業によっては「社内SSO(Oktaなど)」を利用しているケースが多い。
Django では django-allauth を使うことで簡単に統合認証を追加できる。

  • Okta: OIDC 対応、リダイレクト方式
  • Google ログイン: allauth 標準でサポート

👉 まずは「セッション認証」を押さえ、その上でSSOを追加していくのが現実的。


まとめ

  • CORS 設定:Vue から Django API を叩けるようにする
  • セッション認証:社内システムの基本
  • JWT 認証:外部向けAPIやモバイル向け
  • ログイン/ログアウト/ステータスAPI:DRF流に整理
  • 部署・ロールの返却:メニュー制御や承認権限に必須
  • 統合認証:OktaやGoogleを追加できる

👉 これで Vue 側の axios と Django 側のセッション認証がつながり、
さらに部署・ロールに応じたメニュー制御の準備が整った。
次は allauth + Okta ログインについても解説予定。

Discussion