Djangoでの認証のカスタマイズ—Djangoのドキュメント

提供:Dev Guides
< DjangoDjango/docs/3.2.x/topics/auth/customizing
移動先:案内検索

Djangoでの認証のカスタマイズ

Djangoに付属している認証は、ほとんどの一般的なケースには十分ですが、すぐに使用できるデフォルトでは満たす必要がない場合があります。 プロジェクトで認証をカスタマイズするには、提供されたシステムのどのポイントが拡張可能または交換可能であるかを理解する必要があります。 このドキュメントでは、認証システムをカスタマイズする方法について詳しく説明します。

認証バックエンドは、ユーザーモデルに保存されているユーザー名とパスワードをDjangoのデフォルトとは異なるサービスに対して認証する必要がある場合に拡張可能なシステムを提供します。

モデルにカスタム権限を付与して、Djangoの認証システムで確認できます。

デフォルトのUserモデルを拡張することも、完全にカスタマイズされたモデルを置換することもできます。

その他の認証ソース

別の認証ソース、つまり、ユーザー名とパスワードまたは認証方法の別のソースにフックする必要がある場合があります。

たとえば、会社には、すべての従業員のユーザー名とパスワードを格納するLDAP設定がすでにある場合があります。 ユーザーがLDAPとDjangoベースのアプリケーションで別々のアカウントを持っている場合、ネットワーク管理者とユーザー自身の両方にとって面倒です。

したがって、このような状況を処理するために、Django認証システムでは他の認証ソースをプラグインできます。 Djangoのデフォルトのデータベースベースのスキームをオーバーライドすることも、デフォルトのシステムを他のシステムと組み合わせて使用することもできます。

Djangoに含まれている認証バックエンドについては、認証バックエンドリファレンスを参照してください。

認証バックエンドの指定

舞台裏では、Djangoは認証をチェックする「認証バックエンド」のリストを維持しています。 誰かが django.contrib.auth.authenticate()を呼び出すと、ユーザーのログイン方法で説明されているように、Djangoはすべての認証バックエンドで認証を試みます。 最初の認証方法が失敗した場合、Djangoはすべてのバックエンドが試行されるまで、2番目の認証方法を試行します。

使用する認証バックエンドのリストは、:setting: `AUTHENTICATION_BACKENDS` 設定で指定されます。 これは、認証方法を知っているPythonクラスを指すPythonパス名のリストである必要があります。 これらのクラスは、Pythonパスのどこにあってもかまいません。

デフォルトでは、:setting: `AUTHENTICATION_BACKENDS` は次のように設定されています。

['django.contrib.auth.backends.ModelBackend']

これは、Djangoユーザーデータベースをチェックし、組み込みの権限を照会する基本認証バックエンドです。 レート制限メカニズムを介したブルートフォース攻撃に対する保護は提供されません。 カスタム認証バックエンドに独自のレート制限メカニズムを実装するか、ほとんどのWebサーバーが提供するメカニズムを使用することができます。

:setting: `AUTHENTICATION_BACKENDS` の順序が重要であるため、同じユーザー名とパスワードが複数のバックエンドで有効な場合、Djangoは最初の正の一致で処理を停止します。

バックエンドで PermissionDenied 例外が発生した場合、認証はすぐに失敗します。 Djangoは後続のバックエンドをチェックしません。

ノート

ユーザーが認証されると、Djangoはユーザーのセッションでユーザーの認証に使用されたバックエンドを保存し、現在認証されているユーザーへのアクセスが必要な場合はいつでも、そのセッションの間同じバックエンドを再利用します。 これは事実上、認証ソースがセッションごとにキャッシュされることを意味します。したがって、:setting: `AUTHENTICATION_BACKENDS` を変更した場合、ユーザーに再試行を強制する必要がある場合は、セッションデータをクリアする必要があります。さまざまな方法を使用して認証します。 これを行う簡単な方法は、Session.objects.all().delete()を実行することです。


認証バックエンドの作成

認証バックエンドは、get_user(user_id)authenticate(request, **credentials)の2つの必須メソッドと、承認メソッドに関連するオプションの権限のセットを実装するクラスです。

get_userメソッドは、user_id(ユーザー名、データベースIDなどですが、ユーザーオブジェクトの主キーである必要があります)を受け取り、ユーザーオブジェクトまたは [を返します。 X178X]。

authenticateメソッドは、request引数と資格情報をキーワード引数として受け取ります。 ほとんどの場合、次のようになります。

from django.contrib.auth.backends import BaseBackend

class MyBackend(BaseBackend):
    def authenticate(self, request, username=None, password=None):
        # Check the username/password and return a user.
        ...

ただし、次のようにトークンを認証することもできます。

from django.contrib.auth.backends import BaseBackend

class MyBackend(BaseBackend):
    def authenticate(self, request, token=None):
        # Check the token and return a user.
        ...

いずれにせよ、authenticate()は取得した資格情報を確認し、資格情報が有効な場合はそれらの資格情報に一致するユーザーオブジェクトを返す必要があります。 無効な場合は、Noneを返す必要があります。

requestHttpRequest であり、 authenticate()(バックエンドに渡される)に提供されなかった場合はNoneになる可能性があります。

Django管理者は、Django ユーザーオブジェクトと緊密に結合されています。 これに対処する最善の方法は、バックエンドに存在するユーザーごとにDjango Userオブジェクトを作成することです(たとえば、LDAPディレクトリ、外部SQLデータベースなど)。事前にこれを行うか、authenticateメソッドでユーザーが最初にログインしたときにこれを行うことができます。

これは、settings.pyファイルで定義されたユーザー名とパスワードの変数に対して認証し、ユーザーが最初に認証したときにDjango Userオブジェクトを作成するバックエンドの例です。

from django.conf import settings
from django.contrib.auth.backends import BaseBackend
from django.contrib.auth.hashers import check_password
from django.contrib.auth.models import User

class SettingsBackend(BaseBackend):
    """
    Authenticate against the settings ADMIN_LOGIN and ADMIN_PASSWORD.

    Use the login name and a hash of the password. For example:

    ADMIN_LOGIN = 'admin'
    ADMIN_PASSWORD = 'pbkdf2_sha256$30000$Vo0VlMnkR4Bk$qEvtdyZRWTcOsCnI/oQ7fVOu1XAURIZYoOZ3iq8Dr4M='
    """

    def authenticate(self, request, username=None, password=None):
        login_valid = (settings.ADMIN_LOGIN == username)
        pwd_valid = check_password(password, settings.ADMIN_PASSWORD)
        if login_valid and pwd_valid:
            try:
                user = User.objects.get(username=username)
            except User.DoesNotExist:
                # Create a new user. There's no need to set a password
                # because only the password from settings.py is checked.
                user = User(username=username)
                user.is_staff = True
                user.is_superuser = True
                user.save()
            return user
        return None

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

カスタムバックエンドでの承認の処理

カスタム認証バックエンドは、独自の権限を提供できます。

ユーザーモデルとそのマネージャーは、アクセス許可ルックアップ関数( get_user_permissions()get_group_permissions()get_all_permissions()、 has_perm()[X187X ]、 has_module_perms()、および with_perm())を、これらの関数を実装する任意の認証バックエンドに送信します。

ユーザーに付与されるアクセス許可は、すべてのバックエンドによって返されるすべてのアクセス許可のスーパーセットになります。 つまり、Djangoは、いずれかのバックエンドが付与する権限をユーザーに付与します。

バックエンドが has_perm()または has_module_perms()PermissionDenied 例外を発生させた場合、認証はすぐに失敗し、Djangoは後続のバックエンドをチェックしません。

バックエンドは、次のようにマジック管理者の権限を実装できます。

from django.contrib.auth.backends import BaseBackend

class MagicAdminBackend(BaseBackend):
    def has_perm(self, user_obj, perm, obj=None):
        return user_obj.username == settings.ADMIN_LOGIN

これにより、上記の例でアクセスを許可されたユーザーに完全なアクセス許可が与えられます。 関連する django.contrib.auth.models.User 関数に与えられた同じ引数に加えて、バックエンドの認証関数はすべて、匿名ユーザーである可能性のあるユーザーオブジェクトを引数として受け取ることに注意してください。

完全な認証の実装は、:source: `django / contrib / auth / backends.py`ModelBackendクラスにあります。これは、デフォルトのバックエンドであり、 [をクエリします。 X176X]ほとんどの場合テーブル。

匿名ユーザーの承認

匿名ユーザーとは、認証されていないユーザーです。 有効な認証の詳細は提供されていません。 しかし、それは必ずしも彼らが何もすることを許可されていないことを意味するわけではありません。 最も基本的なレベルでは、ほとんどのWebサイトは匿名ユーザーにサイトのほとんどを閲覧することを許可しており、多くのWebサイトはコメントなどの匿名投稿を許可しています。

Djangoの権限フレームワークには、匿名ユーザーの権限を保存する場所がありません。 ただし、認証バックエンドに渡されるユーザーオブジェクトは django.contrib.auth.models.AnonymousUser オブジェクトである可能性があり、バックエンドが匿名ユーザーのカスタム認証動作を指定できるようにします。 これは、たとえば匿名アクセスを制御するための設定を必要とせずに、承認に関するすべての質問を認証バックエンドに委任できる再利用可能なアプリの作成者にとって特に便利です。


非アクティブなユーザーの承認

非アクティブなユーザーとは、 is_active フィールドがFalseに設定されているユーザーです。 ModelBackend および RemoteUserBackend 認証バックエンドは、これらのユーザーの認証を禁止します。 カスタムユーザーモデルに is_active フィールドがない場合、すべてのユーザーが認証を許可されます。

非アクティブなユーザーに認証を許可する場合は、 AllowAllUsersModelBackend または AllowAllUsersRemoteUserBackend を使用できます。

権限システムでの匿名ユーザーのサポートにより、匿名ユーザーには何かを行う権限があり、非アクティブな認証済みユーザーにはないシナリオが可能になります。

独自のバックエンド権限メソッドでユーザーのis_active属性をテストすることを忘れないでください。


オブジェクトのアクセス許可の処理

Djangoのパーミッションフレームワークにはオブジェクトパーミッションの基盤がありますが、コアには実装されていません。 つまり、オブジェクトのアクセス許可をチェックすると、常にFalseまたは空のリスト(実行されたチェックに応じて)が返されます。 認証バックエンドは、オブジェクト関連の承認方法ごとにキーワードパラメータobjおよびuser_objを受け取り、必要に応じてオブジェクトレベルの権限を返すことができます。


カスタム権限

特定のモデルオブジェクトのカスタム権限を作成するには、permissions モデルメタ属性を使用します。

この例のTaskモデルは、2つのカスタム権限を作成します。つまり、アプリケーションに固有のTaskインスタンスでユーザーが実行できるアクションと実行できないアクションです。

class Task(models.Model):
    ...
    class Meta:
        permissions = [
            ("change_task_status", "Can change the status of tasks"),
            ("close_task", "Can remove a task by setting its status as closed"),
        ]

これが行う唯一のことは、実行時にそれらの追加のアクセス許可を作成することです :djadmin: `manage.py移行 ` (権限を作成する関数はに接続されています post_migrate 信号)。 ユーザーがアプリケーションによって提供される機能にアクセスしようとしているとき(タスクのステータスの変更またはタスクの終了)、コードはこれらのアクセス許可の値のチェックを担当します。上記の例を続けて、以下はユーザーがタスクを閉じることができるかどうかをチェックします。 :

user.has_perm('app.close_task')

既存のUserモデルの拡張

独自のモデルを置き換えることなく、デフォルトの User モデルを拡張する方法は2つあります。 必要な変更が純粋に動作であり、データベースに保存されているものを変更する必要がない場合は、ユーザーに基づいてプロキシモデルを作成できます。 これにより、デフォルトの順序付け、カスタムマネージャー、カスタムモデルメソッドなど、プロキシモデルによって提供されるすべての機能が可能になります。

Userに関連する情報を保存する場合は、 OneToOneField を使用して、追加情報のフィールドを含むモデルを作成できます。 この1対1モデルは、サイトユーザーに関する認証に関連しない情報を格納する可能性があるため、プロファイルモデルと呼ばれることがよくあります。 たとえば、次のような従業員モデルを作成できます。

from django.contrib.auth.models import User

class Employee(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    department = models.CharField(max_length=100)

ユーザーモデルと従業員モデルの両方を持っている既存の従業員FredSmithを想定すると、Djangoの標準の関連モデル規則を使用して関連情報にアクセスできます。

>>> u = User.objects.get(username='fsmith')
>>> freds_department = u.employee.department

管理者のユーザーページにプロファイルモデルのフィールドを追加するには、アプリのadmin.pyInlineModelAdmin (この例では StackedInline を使用します)を定義します。 User クラスに登録されているUserAdminクラスに追加します。

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.models import User

from my_user_profile_app.models import Employee

# Define an inline admin descriptor for Employee model
# which acts a bit like a singleton
class EmployeeInline(admin.StackedInline):
    model = Employee
    can_delete = False
    verbose_name_plural = 'employee'

# Define a new User admin
class UserAdmin(BaseUserAdmin):
    inlines = (EmployeeInline,)

# Re-register UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)

これらのプロファイルモデルは決して特別なものではありません。ユーザーモデルと1対1のリンクを持っているDjangoモデルにすぎません。 そのため、ユーザーの作成時に自動作成されることはありませんが、 django.db.models.signals.post_save を使用して、必要に応じて関連モデルを作成または更新できます。

関連モデルを使用すると、関連データを取得するための追加のクエリまたは結合が発生します。 必要に応じて、関連フィールドを含むカスタムユーザーモデルの方が適している場合がありますが、プロジェクトのアプリ内のデフォルトのユーザーモデルとの既存の関係により、データベースの追加負荷が正当化される場合があります。


カスタムUserモデルの置き換え

一部の種類のプロジェクトには、Djangoの組み込み User モデルが常に適切であるとは限らない認証要件がある場合があります。 たとえば、一部のサイトでは、ユーザー名の代わりに電子メールアドレスを識別トークンとして使用する方が理にかなっています。

Djangoでは、カスタムモデルを参照する:setting: `AUTH_USER_MODEL` 設定の値を指定することで、デフォルトのユーザーモデルをオーバーライドできます。

AUTH_USER_MODEL = 'myapp.MyUser'

この点線のペアは、Djangoアプリの名前(:setting: `INSTALLED_APPS` に含まれている必要があります)と、ユーザーモデルとして使用するDjangoモデルの名前を示しています。

プロジェクトの開始時にカスタムユーザーモデルを使用する

新しいプロジェクトを開始する場合は、デフォルトのユーザーモデルで十分な場合でも、カスタムユーザーモデルを設定することを強くお勧めします。 このモデルはデフォルトのユーザーモデルと同じように動作しますが、必要に応じて将来カスタマイズすることができます。

from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
    pass

:setting: `AUTH_USER_MODEL` を指すことを忘れないでください。 移行を作成する前、またはmanage.py migrateを初めて実行する前に、これを実行してください。

また、アプリのadmin.pyにモデルを登録します。

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import User

admin.site.register(User, UserAdmin)

プロジェクトの途中でカスタムユーザーモデルに変更する

データベーステーブルの作成後に:setting: `AUTH_USER_MODEL` を変更すると、外部キーや多対多の関係などに影響するため、非常に困難になります。

この変更は自動的に行うことはできず、スキーマを手動で修正し、古いユーザーテーブルからデータを移動し、場合によっては一部の移行を手動で再適用する必要があります。 手順の概要については、:ticket: `25313` を参照してください。

スワップ可能なモデルに対するDjangoの動的依存関係機能の制限により、:setting: `AUTH_USER_MODEL` で参照されるモデルは、アプリの最初の移行時に作成する必要があります(通常は0001_initialと呼ばれます)。 そうしないと、依存関係の問題が発生します。

さらに、動的な依存関係のためにDjangoが依存関係ループを自動的に解除できないため、移行の実行時にCircularDependencyErrorが発生する可能性があります。 このエラーが表示された場合は、ユーザーモデルに依存するモデルを2番目の移行に移動して、ループを解除する必要があります。 (ForeignKeyを相互に持つ2つの正規モデルを作成し、通常の方法を確認したい場合は、makemigrationsがその循環依存関係をどのように解決するかを確認できます。)


再利用可能なアプリとAUTH_USER_MODEL

再利用可能なアプリは、カスタムユーザーモデルを実装するべきではありません。 プロジェクトは多くのアプリを使用する可能性があり、カスタムユーザーモデルを実装した2つの再利用可能なアプリを一緒に使用することはできませんでした。 アプリにユーザーごとの情報を保存する必要がある場合は、以下の説明に従って、 ForeignKey または OneToOneField からsettings.AUTH_USER_MODELを使用します。


Userモデルを参照する

User を直接参照する場合(たとえば、外部キーで参照する場合)、:setting: `AUTH_USER_MODEL` 設定が変更されたプロジェクトではコードが機能しません。別のユーザーモデルに。

get_user_model()

User を直接参照する代わりに、django.contrib.auth.get_user_model()を使用してユーザーモデルを参照する必要があります。 このメソッドは、現在アクティブなユーザーモデルを返します。指定されている場合はカスタムユーザーモデル、それ以外の場合は User を返します。

ユーザーモデルに対して外部キーまたは多対多の関係を定義する場合は、:setting: `AUTH_USER_MODEL` 設定を使用してカスタムモデルを指定する必要があります。 例えば:

from django.conf import settings
from django.db import models

class Article(models.Model):
    author = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
    )

ユーザーモデルから送信される信号に接続する場合は、:setting: `AUTH_USER_MODEL` 設定でカスタムモデルを指定する必要があります。 例えば:

from django.conf import settings
from django.db.models.signals import post_save

def post_save_receiver(sender, instance, created, **kwargs):
    pass

post_save.connect(post_save_receiver, sender=settings.AUTH_USER_MODEL)

一般的に、インポート時に実行されるコードで:setting: `AUTH_USER_MODEL` 設定を使用してユーザーモデルを参照するのが最も簡単ですが、Djangoが実行されている間にget_user_model()を呼び出すこともできます。モデルをインポートするので、models.ForeignKey(get_user_model(), ...)を使用できます。

アプリが@override_settings(AUTH_USER_MODEL=...)などを使用して複数のユーザーモデルでテストされ、get_user_model()の結果をモジュールレベルの変数にキャッシュする場合、 setting_changedをリッスンする必要がある場合があります。 キャッシュをクリアする信号。 例えば:

from django.apps import apps
from django.contrib.auth import get_user_model
from django.core.signals import setting_changed
from django.dispatch import receiver

@receiver(setting_changed)
def user_model_swapped(**kwargs):
    if kwargs['setting'] == 'AUTH_USER_MODEL':
        apps.clear_cache()
        from myapp import some_module
        some_module.UserModel = get_user_model()


カスタムユーザーモデルの指定

カスタムユーザーモデルを使用してプロジェクトを開始するときは、これがプロジェクトにとって正しい選択であるかどうかを検討するのをやめてください。

すべてのユーザー関連情報を1つのモデルに保持することで、関連モデルを取得するための追加またはより複雑なデータベースクエリが不要になります。 一方、カスタムユーザーモデルと関係のあるモデルにアプリ固有のユーザー情報を保存する方が適切な場合があります。 これにより、各アプリは、他のアプリによる想定と矛盾したり破られたりすることなく、独自のユーザーデータ要件を指定できます。 また、ユーザーモデルを可能な限りシンプルに保ち、認証に重点を置き、Djangoがカスタムユーザーモデルが満たすと期待する最小要件に従うことも意味します。

デフォルトの認証バックエンドを使用する場合、モデルには、識別目的で使用できる単一の一意のフィールドが必要です。 これは、ユーザー名、電子メールアドレス、またはその他の一意の属性にすることができます。 一意でないユーザー名フィールドは、それをサポートできるカスタム認証バックエンドを使用する場合に許可されます。

準拠したカスタムユーザーモデルを構築する最も簡単な方法は、 AbstractBaseUser から継承することです。 AbstractBaseUser は、ハッシュ化されたパスワードやトークン化されたパスワードのリセットなど、ユーザーモデルのコア実装を提供します。 次に、いくつかの重要な実装の詳細を提供する必要があります。

class models.CustomUser
USERNAME_FIELD

一意の識別子として使用されるユーザーモデルのフィールドの名前を説明する文字列。 これは通常、ある種のユーザー名になりますが、電子メールアドレスやその他の一意の識別子にすることもできます。 一意でないユーザー名をサポートできるカスタム認証バックエンドを使用しない限り、フィールドは一意である必要があります(つまり、unique=Trueが定義に設定されている)。

次の例では、フィールドidentifierが識別フィールドとして使用されています。

class MyUser(AbstractBaseUser):
    identifier = models.CharField(max_length=40, unique=True)
    ...
    USERNAME_FIELD = 'identifier'
EMAIL_FIELD

Userモデルの電子メールフィールドの名前を説明する文字列。 この値は、 get_email_field_name()によって返されます。

REQUIRED_FIELDS

:djadmin: `createsuperuser` 管理コマンドを使用してユーザーを作成するときにプロンプトが表示されるフィールド名のリスト。 ユーザーは、これらの各フィールドに値を入力するように求められます。 空白Falseまたは未定義のフィールドを含める必要があり、ユーザーがインタラクティブに作成されたときにプロンプトが表示される追加のフィールドを含めることができます。 REQUIRED_FIELDSは、管理者でユーザーを作成するなど、Djangoの他の部分では効果がありません。

たとえば、生年月日と身長の2つの必須フィールドを定義するユーザーモデルの部分的な定義は次のとおりです。

class MyUser(AbstractBaseUser):
    ...
    date_of_birth = models.DateField()
    height = models.FloatField()
    ...
    REQUIRED_FIELDS = ['date_of_birth', 'height']

ノート

REQUIRED_FIELDSには、ユーザーモデルのすべての必須フィールドが含まれている必要がありますが、にはUSERNAME_FIELDまたはpasswordが含まれていない必要があります。これらのフィールドは、常にプロンプトが表示されるためです。

is_active

ユーザーが「アクティブ」と見なされるかどうかを示すブール属性。 この属性は、デフォルトでTrueに設定されているAbstractBaseUserの属性として提供されます。 どのように実装するかは、選択した認証バックエンドの詳細によって異なります。 詳細については、組み込みユーザーモデル is_active属性のドキュメントを参照してください。

get_full_name()

オプション。 フルネームなど、ユーザーのより長い正式な識別子。 実装されている場合、これは django.contrib.admin のオブジェクトの履歴にユーザー名と一緒に表示されます。

get_short_name()

オプション。 名など、ユーザーの短い非公式の識別子。 実装されている場合、これは django.contrib.admin のヘッダーにあるユーザーへの挨拶のユーザー名を置き換えます。

AbstractBaseUserをインポートしています

AbstractBaseUserBaseUserManagerdjango.contrib.auth.base_userからインポートできるため、:setting: `INSTALLED_APPS`django.contrib.authを含めずにインポートできます。

次の属性とメソッドは、 AbstractBaseUser のすべてのサブクラスで使用できます。

class models.AbstractBaseUser
get_username()

USERNAME_FIELDで指定されたフィールドの値を返します。

clean()

normalize_username()を呼び出して、ユーザー名を正規化します。 このメソッドをオーバーライドする場合は、必ずsuper()を呼び出して正規化を保持してください。

classmethod get_email_field_name()

EMAIL_FIELD 属性で指定された電子メールフィールドの名前を返します。 EMAIL_FIELDが指定されていない場合、デフォルトは'email'です。

classmethod normalize_username(username)

NFKC Unicode正規化をユーザー名に適用して、異なるUnicodeコードポイントを持つ視覚的に同一の文字が同一であると見なされるようにします。

is_authenticated

常にTrueである読み取り専用属性(常にFalseであるAnonymousUser.is_authenticatedとは対照的)。 これは、ユーザーが認証されているかどうかを確認する方法です。 これは、権限を意味するものではなく、ユーザーがアクティブであるか、有効なセッションを持っているかどうかを確認しません。 通常、request.userでこの属性をチェックして、 AuthenticationMiddleware (現在ログインしているユーザーを表す)によって入力されているかどうかを確認しますが、この属性がTrue任意のユーザーインスタンス。

is_anonymous

常にFalseである読み取り専用属性。 これは、 User オブジェクトと AnonymousUser オブジェクトを区別する方法です。 通常、この属性よりも is_authenticated を使用することをお勧めします。

set_password(raw_password)

パスワードのハッシュを処理しながら、ユーザーのパスワードを指定された生の文字列に設定します。 AbstractBaseUser オブジェクトを保存しません。

raw_passwordがNoneの場合、 set_unusable_password()が使用されたかのように、パスワードは使用できないパスワードに設定されます。

check_password(raw_password)

指定された生の文字列がユーザーの正しいパスワードである場合、Trueを返します。 (これにより、比較を行う際のパスワードハッシュが処理されます。)

set_unusable_password()

パスワードが設定されていないことをユーザーにマークします。 これは、パスワードに空白の文字列を使用することと同じではありません。 このユーザーの check_password()は、Trueを返すことはありません。 AbstractBaseUser オブジェクトを保存しません。

アプリケーションの認証がLDAPディレクトリなどの既存の外部ソースに対して行われる場合は、これが必要になることがあります。

has_usable_password()

このユーザーに対して set_unusable_password()が呼び出された場合、Falseを返します。

get_session_auth_hash()

パスワードフィールドのHMACを返します。 パスワード変更時のセッション無効化に使用されます。

バージョン3.1で変更:ハッシュアルゴリズムがSHA-256に変更されました。

AbstractUser サブクラス AbstractBaseUser

class models.AbstractUser
;; clean()
BaseUserManager.normalize_email()を呼び出して、電子メールを正規化します。 このメソッドをオーバーライドする場合は、必ずsuper()を呼び出して正規化を保持してください。


カスタムユーザーモデルのマネージャーを作成する

また、ユーザーモデルのカスタムマネージャーを定義する必要があります。 ユーザーモデルでusernameemailis_staffis_activeis_superuserlast_login、[X97X ] フィールドはDjangoのデフォルトユーザーと同じで、Djangoの UserManager をインストールできます。 ただし、ユーザーモデルで異なるフィールドを定義する場合は、 BaseUserManager を拡張して2つの追加メソッドを提供するカスタムマネージャーを定義する必要があります。

class models.CustomUserManager
create_user(username_field, password=None, **other_fields)

create_user()のプロトタイプは、ユーザー名フィールドに加えて、すべての必須フィールドを引数として受け入れる必要があります。 たとえば、ユーザーモデルがユーザー名フィールドとしてemailを使用し、必須フィールドとしてdate_of_birthがある場合、create_userは次のように定義する必要があります。

def create_user(self, email, date_of_birth, password=None):
    # create user here
    ...
create_superuser(username_field, password=None, **other_fields)

create_superuser()のプロトタイプは、ユーザー名フィールドに加えて、すべての必須フィールドを引数として受け入れる必要があります。 たとえば、ユーザーモデルがユーザー名フィールドとしてemailを使用し、必須フィールドとしてdate_of_birthがある場合、create_superuserは次のように定義する必要があります。

def create_superuser(self, email, date_of_birth, password=None):
    # create superuser here
    ...

USERNAME_FIELD または REQUIRED_FIELDSForeignKey の場合、これらのメソッドは to_fieldprimary_key byデフォルト)既存のインスタンスの。

BaseUserManager は、次のユーティリティメソッドを提供します。

class models.BaseUserManager
classmethod normalize_email(email)

電子メールアドレスのドメイン部分を小文字にすることにより、電子メールアドレスを正規化します。

get_by_natural_key(username)

USERNAME_FIELDで指定されたフィールドの内容を使用してユーザーインスタンスを取得します。

make_random_password(length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789')

指定された長さと許可された文字列のランダムなパスワードを返します。 allowed_charsのデフォルト値には、次のようなユーザーの混乱を引き起こす可能性のある文字が含まれていないことに注意してください。

  • ilI、および1(小文字i、小文字L、大文字i、および番号1)

  • oO、および0(小文字のo、大文字のo、およびゼロ)


Djangoのデフォルトの拡張User

Djangoの User モデルに完全に満足しているが、プロファイル情報を追加したい場合は、 django.contrib.auth.models.AbstractUser をサブクラス化してカスタムプロファイルを追加できます。 カスタムユーザーモデルの指定の「モデル設計の考慮事項」の注記で説明されているように、別のモデルをお勧めします。 AbstractUserは、デフォルトの User の完全な実装を抽象モデルとして提供します。


カスタムユーザーと組み込みの認証フォーム

Djangoの組み込みのフォームおよびビューは、使用しているユーザーモデルについて特定の仮定を行っています。

次のフォームは、 AbstractBaseUser のすべてのサブクラスと互換性があります。

次のフォームは、ユーザーモデルに関する仮定を作成し、それらの仮定が満たされている場合はそのまま使用できます。

  • PasswordResetForm :ユーザーモデルに、 get_email_field_name()(デフォルトではemail)によって返される名前のユーザーの電子メールアドレスを格納するフィールドがあると想定します。ユーザーとis_activeという名前のブールフィールドを識別して、非アクティブなユーザーのパスワードがリセットされないようにします。

最後に、次のフォームは User に関連付けられており、カスタムユーザーモデルで機能するように書き直すか拡張する必要があります。

カスタムユーザーモデルがAbstractUserのサブクラスである場合、次の方法でこれらのフォームを拡張できます。

from django.contrib.auth.forms import UserCreationForm
from myapp.models import CustomUser

class CustomUserCreationForm(UserCreationForm):

    class Meta(UserCreationForm.Meta):
        model = CustomUser
        fields = UserCreationForm.Meta.fields + ('custom_field',)

カスタムユーザーと django.contrib.admin

カスタムユーザーモデルを管理者とも連携させる場合は、ユーザーモデルでいくつかの追加の属性とメソッドを定義する必要があります。 これらのメソッドにより、管理者は管理コンテンツへのユーザーのアクセスを制御できます。

class models.CustomUser
is_staff
ユーザーが管理サイトへのアクセスを許可されている場合は、Trueを返します。
is_active
ユーザーアカウントが現在アクティブな場合は、Trueを返します。
has_perm(perm, obj=None):
ユーザーが指定された権限を持っている場合、Trueを返します。 objが指定されている場合は、特定のオブジェクトインスタンスに対して権限を確認する必要があります。
has_module_perms(app_label):
ユーザーが指定されたアプリのモデルにアクセスする権限を持っている場合、Trueを返します。

また、カスタムユーザーモデルを管理者に登録する必要があります。 カスタムユーザーモデルがdjango.contrib.auth.models.AbstractUserを拡張する場合は、Djangoの既存のdjango.contrib.auth.admin.UserAdminクラスを使用できます。 ただし、ユーザーモデルが AbstractBaseUser を拡張する場合は、カスタムModelAdminクラスを定義する必要があります。 デフォルトのdjango.contrib.auth.admin.UserAdminをサブクラス化できる場合があります。 ただし、カスタムユーザークラスにないdjango.contrib.auth.models.AbstractUserのフィールドを参照する定義をオーバーライドする必要があります。

ノート

django.contrib.auth.admin.UserAdminのサブクラスであるカスタムModelAdminを使用している場合は、カスタムフィールドをfieldsets(ユーザーの編集に使用するフィールド用)に追加する必要があります。 〜add_fieldsets(ユーザー作成時に使用するフィールド用)。 例えば:

from django.contrib.auth.admin import UserAdmin

class CustomUserAdmin(UserAdmin):
    ...
    fieldsets = UserAdmin.fieldsets + (
        (None, {'fields': ('custom_field',)}),
    )
    add_fieldsets = UserAdmin.add_fieldsets + (
        (None, {'fields': ('custom_field',)}),
    )

詳細については、完全な例を参照してください。


カスタムユーザーと権限

Djangoのパーミッションフレームワークを独自のユーザークラスに簡単に含めることができるように、Djangoは PermissionsMixin を提供しています。 これは、ユーザーモデルのクラス階層に含めることができる抽象モデルであり、Djangoのアクセス許可モデルをサポートするために必要なすべてのメソッドとデータベースフィールドを提供します。

PermissionsMixin は、次のメソッドと属性を提供します。

class models.PermissionsMixin
is_superuser

ブール値。 このユーザーが明示的に割り当てずにすべての権限を持っていることを指定します。

get_user_permissions(obj=None)

ユーザーが直接持っている一連のアクセス許可文字列を返します。

objが渡された場合、この特定のオブジェクトのユーザー権限のみを返します。

get_group_permissions(obj=None)

グループを通じて、ユーザーが持っている一連のアクセス許可文字列を返します。

objが渡された場合、この特定のオブジェクトのグループ権限のみを返します。

get_all_permissions(obj=None)

グループ権限とユーザー権限の両方を通じて、ユーザーが持っている権限文字列のセットを返します。

objが渡された場合、この特定のオブジェクトのアクセス許可のみが返されます。

has_perm(perm, obj=None)

ユーザーが指定された権限を持っている場合、Trueを返します。ここで、perm"<app label>.<permission codename>"の形式です(権限を参照)。 User.is_activeis_superuser が両方ともTrueの場合、このメソッドは常にTrueを返します。

objが渡された場合、このメソッドはモデルのアクセス許可をチェックしませんが、この特定のオブジェクトのアクセス許可をチェックします。

has_perms(perm_list, obj=None)

ユーザーが指定された各権限を持っている場合、Trueを返します。各権限は、"<app label>.<permission codename>"の形式です。 User.is_activeis_superuser が両方ともTrueの場合、このメソッドは常にTrueを返します。

objが渡された場合、このメソッドはモデルの権限ではなく、特定のオブジェクトの権限を確認します。

has_module_perms(package_name)

ユーザーが指定されたパッケージ(Djangoアプリラベル)で何らかの権限を持っている場合、Trueを返します。 User.is_activeis_superuser が両方ともTrueの場合、このメソッドは常にTrueを返します。

PermissionsMixinおよびModelBackend

PermissionsMixin を含めない場合は、ModelBackendでアクセス許可メソッドを呼び出さないようにする必要があります。 ModelBackendは、特定のフィールドがユーザーモデルで使用可能であることを前提としています。 ユーザーモデルでこれらのフィールドが提供されていない場合は、アクセス許可を確認するときにデータベースエラーが発生します。


カスタムユーザーとプロキシモデル

カスタムユーザーモデルの制限の1つは、カスタムユーザーモデルをインストールすると、ユーザーを拡張するプロキシモデルが破損することです。 プロキシモデルは、具体的な基本クラスに基づいている必要があります。 カスタムユーザーモデルを定義することで、基本クラスを確実に識別するDjangoの機能を削除します。

プロジェクトでプロキシモデルを使用する場合は、プロキシを変更してプロジェクトで使用されているユーザーモデルを拡張するか、プロキシの動作を User サブクラスにマージする必要があります。


完全な例

これは、管理者準拠のカスタムユーザーアプリの例です。 このユーザーモデルは、ユーザー名として電子メールアドレスを使用し、必要な生年月日があります。 ユーザーアカウントのadminフラグ以外の権限チェックは提供されません。 このモデルは、ユーザー作成フォームを除く、すべての組み込みの認証フォームおよびビューと互換性があります。 この例は、ほとんどのコンポーネントがどのように連携するかを示していますが、本番環境で使用するためにプロジェクトに直接コピーすることを意図したものではありません。

このコードはすべて、カスタム認証アプリのmodels.pyファイルに存在します。

from django.db import models
from django.contrib.auth.models import (
    BaseUserManager, AbstractBaseUser
)


class MyUserManager(BaseUserManager):
    def create_user(self, email, date_of_birth, password=None):
        """
        Creates and saves a User with the given email, date of
        birth and password.
        """
        if not email:
            raise ValueError('Users must have an email address')

        user = self.model(
            email=self.normalize_email(email),
            date_of_birth=date_of_birth,
        )

        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, date_of_birth, password=None):
        """
        Creates and saves a superuser with the given email, date of
        birth and password.
        """
        user = self.create_user(
            email,
            password=password,
            date_of_birth=date_of_birth,
        )
        user.is_admin = True
        user.save(using=self._db)
        return user


class MyUser(AbstractBaseUser):
    email = models.EmailField(
        verbose_name='email address',
        max_length=255,
        unique=True,
    )
    date_of_birth = models.DateField()
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)

    objects = MyUserManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['date_of_birth']

    def __str__(self):
        return self.email

    def has_perm(self, perm, obj=None):
        "Does the user have a specific permission?"
        # Simplest possible answer: Yes, always
        return True

    def has_module_perms(self, app_label):
        "Does the user have permissions to view the app `app_label`?"
        # Simplest possible answer: Yes, always
        return True

    @property
    def is_staff(self):
        "Is the user a member of staff?"
        # Simplest possible answer: All admins are staff
        return self.is_admin

次に、このカスタムユーザーモデルをDjangoの管理者に登録するには、アプリのadmin.pyファイルに次のコードが必要です。

from django import forms
from django.contrib import admin
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from django.core.exceptions import ValidationError

from customauth.models import MyUser


class UserCreationForm(forms.ModelForm):
    """A form for creating new users. Includes all the required
    fields, plus a repeated password."""
    password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
    password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)

    class Meta:
        model = MyUser
        fields = ('email', 'date_of_birth')

    def clean_password2(self):
        # Check that the two password entries match
        password1 = self.cleaned_data.get("password1")
        password2 = self.cleaned_data.get("password2")
        if password1 and password2 and password1 != password2:
            raise ValidationError("Passwords don't match")
        return password2

    def save(self, commit=True):
        # Save the provided password in hashed format
        user = super().save(commit=False)
        user.set_password(self.cleaned_data["password1"])
        if commit:
            user.save()
        return user


class UserChangeForm(forms.ModelForm):
    """A form for updating users. Includes all the fields on
    the user, but replaces the password field with admin's
    disabled password hash display field.
    """
    password = ReadOnlyPasswordHashField()

    class Meta:
        model = MyUser
        fields = ('email', 'password', 'date_of_birth', 'is_active', 'is_admin')


class UserAdmin(BaseUserAdmin):
    # The forms to add and change user instances
    form = UserChangeForm
    add_form = UserCreationForm

    # The fields to be used in displaying the User model.
    # These override the definitions on the base UserAdmin
    # that reference specific fields on auth.User.
    list_display = ('email', 'date_of_birth', 'is_admin')
    list_filter = ('is_admin',)
    fieldsets = (
        (None, {'fields': ('email', 'password')}),
        ('Personal info', {'fields': ('date_of_birth',)}),
        ('Permissions', {'fields': ('is_admin',)}),
    )
    # add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
    # overrides get_fieldsets to use this attribute when creating a user.
    add_fieldsets = (
        (None, {
            'classes': ('wide',),
            'fields': ('email', 'date_of_birth', 'password1', 'password2'),
        }),
    )
    search_fields = ('email',)
    ordering = ('email',)
    filter_horizontal = ()


# Now register the new UserAdmin...
admin.site.register(MyUser, UserAdmin)
# ... and, since we're not using Django's built-in permissions,
# unregister the Group model from admin.
admin.site.unregister(Group)

最後に、settings.py:setting: `AUTH_USER_MODEL` 設定を使用して、プロジェクトのデフォルトのユーザーモデルとしてカスタムモデルを指定します。

AUTH_USER_MODEL = 'customauth.MyUser'

バージョン3.2で変更:古いバージョンでは、ReadOnlyPasswordHashFieldはデフォルトで無効ではなく、UserChangeForm.clean_password()はユーザーに関係なく初期値を返す必要があります提供します。