【Django入門18】ユーザーロールとパーミッションの管理|アクセス制御の基本

ユーザーロールとパーミッションの基本

なぜユーザーロールとパーミッションが重要なのか?

Webアプリケーションでは、ユーザーがアクセスできる情報や実行できる操作を制御する必要があります。たとえば、管理者はすべてのデータにアクセスできるが、一般ユーザーは自分のデータにしかアクセスできないようにする、といったシナリオです。

Djangoでは、ユーザーロール(役割)とパーミッション(権限)を簡単に設定し、アプリケーションのセキュリティを強化するための機能が標準で提供されています。

Djangoの認証と権限システムの概要

Djangoの認証システム

Djangoには、デフォルトでユーザー認証システムが用意されています。このシステムには、次のような機能が含まれています:

  • ユーザーモデル(django.contrib.auth.models.User
  • ログイン、ログアウト、パスワード管理
  • パーミッションとグループによるアクセス制御

パーミッションとグループ

  • パーミッション:各モデルやビューに対してアクセス権限を設定するためのルールです。
  • グループ:複数のユーザーに共通のパーミッションをまとめて割り当てるための機能です。

ユーザーロールの設定

デフォルトのユーザーモデルの確認

Djangoのデフォルトのユーザーモデルには、次のようなフィールドが用意されています:

  • username: ユーザー名
  • email: メールアドレス
  • is_staff: 管理画面にアクセスできるかを示すフラグ
  • is_superuser: すべての権限を持つかを示すフラグ
  • is_active: アカウントが有効かどうかを示すフラグ

例:新しいユーザーの作成

from django.contrib.auth.models import User

# 新しいユーザーを作成
user = User.objects.create_user(username='testuser', password='password123', email='testuser@example.com')

カスタムユーザーモデルの作成

デフォルトのユーザーモデルに必要なフィールドを追加したい場合は、カスタムユーザーモデルを定義できます。

models.py:

from django.contrib.auth.models import AbstractUser
from django.db import models

class CustomUser(AbstractUser):
    bio = models.TextField(blank=True, null=True)  # プロファイル情報

settings.py:

AUTH_USER_MODEL = 'myapp.CustomUser'

パーミッションの設定と管理

モデルレベルのパーミッション

Djangoは自動的に、各モデルに対して次の3つの基本的なパーミッションを作成します:

  • add_<model>: 新しいオブジェクトを追加する権限
  • change_<model>: 既存のオブジェクトを変更する権限
  • delete_<model>: オブジェクトを削除する権限

例:パーミッションの確認と付与

from django.contrib.auth.models import User, Permission
from django.contrib.contenttypes.models import ContentType
from myapp.models import BlogPost

# パーミッションの取得
content_type = ContentType.objects.get_for_model(BlogPost)
permission = Permission.objects.get(codename='change_blogpost', content_type=content_type)

# ユーザーにパーミッションを付与
user = User.objects.get(username='testuser')
user.user_permissions.add(permission)

ビューレベルのパーミッション制御

ビューで特定のパーミッションを要求するには、@permission_requiredデコレーターを使用します。

views.py:

from django.contrib.auth.decorators import permission_required
from django.http import HttpResponse

@permission_required('myapp.change_blogpost', raise_exception=True)
def edit_blogpost(request):
    return HttpResponse("ブログ投稿の編集が許可されています。")
  • raise_exception=True:権限がない場合に403エラーを返します。

グループの使用

グループの作成とパーミッションの割り当て

複数のユーザーに同じ権限を付与する場合は、グループを使うと便利です。

例:グループの作成と設定

from django.contrib.auth.models import Group, Permission
from myapp.models import BlogPost
from django.contrib.contenttypes.models import ContentType

# グループの作成
editors_group = Group.objects.create(name='Editors')

# パーミッションの追加
content_type = ContentType.objects.get_for_model(BlogPost)
permission = Permission.objects.get(codename='change_blogpost', content_type=content_type)
editors_group.permissions.add(permission)

# ユーザーをグループに追加
user = User.objects.get(username='testuser')
user.groups.add(editors_group)

グループベースのアクセス制御

ユーザーが特定のグループに属しているかをチェックすることで、アクセス制御を行うことができます。

views.py:

from django.contrib.auth.decorators import login_required
from django.http import HttpResponse

@login_required
def dashboard_view(request):
    if request.user.groups.filter(name='Editors').exists():
        return HttpResponse("編集者向けのダッシュボードにアクセスできます。")
    else:
        return HttpResponse("アクセスが拒否されました。")

ログインと認証のカスタマイズ

ログイン必須のビュー

Djangoには、ユーザーがログインしているかどうかをチェックする@login_requiredデコレーターが用意されています。

views.py:

from django.contrib.auth.decorators import login_required
from django.shortcuts import render

@login_required
def profile_view(request):
    return render(request, 'profile.html', {'user': request.user})

カスタム認証バックエンド

標準の認証方法(ユーザー名とパスワード)以外に、独自の認証ロジックを実装する場合は、カスタム認証バックエンドを作成できます。

auth_backends.py:

from django.contrib.auth.backends import BaseBackend
from django.contrib.auth.models import User

class EmailAuthBackend(BaseBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        try:
            user = User.objects.get(email=username)
            if user.check_password(password):
                return user
        except User.DoesNotExist:
            return None

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

settings.py:

AUTHENTICATION_BACKENDS = [
    'myapp.auth_backends.EmailAuthBackend',
    'django.contrib.auth.backends.ModelBackend',  # デフォルトのバックエンド
]

まとめ

Djangoのユーザーロールとパーミッション管理は、強力な認証システムを使ってアプリケーションのセキュリティを向上させるための重要な機能です。ユーザーごとのアクセス制御や、グループを使った一括管理、さらにはカスタム認証バックエンドを導入することで、柔軟で安全なアプリケーションを構築できます。