Penyesuaian pembuktian keaslian di Django

Pembuktian keaslian yang datang dengan Django adalah cukup bagus untuk kasus umum, tetapi anda mungkin tidak butuh memenuhi dengan awal out-of-the-box. Untuk menyesuaiakan pembuktian keaslian ke proyek anda butuh melibatkan pemahaman titik apa dari sistem disediakan dapat di perpanjang atau diganti. Dokumen ini menyediakan rincian tentang bagaimana sistem pembuktian keaslian dapat di sesuaikan.

Authentication backends menyediakan sistem dapat diperpanjang untuk ketika nama pengguna dan sandi disimpan dengan model User butuh diperiksa keasliannya terhadap layanan berbeda dari awa Django.

Anda dapat memberikan model anda perizinan perizinan disesuaikan yang dapat diperiksa melalui sistem pemeriksaan keaslian Django.

Anda dapat extend User model awal, atau substitute model disesuaikan yang lengkap.

Sumber pembuktian keaslian lain

Mungkin ada kali anda harus butuh mengait ke dalam sumber pembuktian keaslian lain – yaitu, sumber lain dari nama pengguna dan sandi atau cara pembuktian keaslian.

Sebagai contoh, perusahaan anda mungkin sudah mempunyai pengaturan LDAP yang menyimpan nama pengguna dan sandi untuk setiap karyawan. Itu akan menjadi cekcok untuk kedua administrator jaringan dan pengguna nya sendiri jika pengguna mempunyai akun terpisah di LDAP dan aplikasi berbasis-Django.

Jadi, untuk menangani keadaan seperti ini, sistem pembuktian keaslian Django membiarkan anda memasang sumber pembuktian keaslian lain. Anda dapat mengesampingkan skema berbasis-basisdata awal Django, atau anda dapat menggunakan sistem awal untuk dipasangkan dengan sistem lain.

Lihat acuan backend pembuktian keaslian untuk informasi pada backend pembuktian keaslian yang disertakan dengan Django.

Menentukan backend pembuktian keaslian

Dibelakang layar, Django merawat daftar “backend pembuktian keaslian” yang dia periksa untuk pembuktian keaslian. Ketika seseorang memanggil django.contrib.auth.authenticate() – seperti digambarkan di How to log a user in – Django mencoba membuktikan keaslian disemua bakcend pembuktian keaslian itu. Jika cara pembuktian keaslian pertama gagal, Django mencoba yang kedua, dan selanjutnya, sampai semua backend telah dicoba.

Daftar backend pembuktian keaslian untuk digunakan ditentukan dalam pengaturan AUTHENTICATION_BACKENDS. Ini seharusnya daftar nama jalur Python yang menunjuk ke kelas Python yang mengetahui bagaimana membuktikan keaslian. Kelas ini dapat berada dimanapun di jalur Python anda.

Secara awal, AUTHENTICATION_BACKENDS disetel ke:

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

Itu adalah backend pembuktian keaslian dasar yang memeriksa basisdata pengguna Django dan permintaan perizinan terpasang-tetap. Dia tidak menyediakan perlindungan terhadap serangan paksa brutal melalui mekanisme pembatasan apapun. Anda dapat salah satu menerapkan mekanisme pembatasan laju anda sendiri di backend pembuktian keaslian penyesuaian, atau menggunakan mekanisme yang disediakan oleh kebanyakan peladen Jaringan.

Urutan masalah AUTHENTICATION_BACKENDS, jadi jika nama pengguna dan sandi sama adalah sah di banyak backend, Django akan menghentikan pengolahan pada pertama yang positif cocok.

Jika backend memunculkan pengecualian PermissionDenied, pembuktian keaslian akan segera gagal. Django tidak akan memeriksa backend yang mengikuti.

Catatan

Sekali pengguna telah dibuktikan keasliannya, Django menyimpan backend mana yang telah digunakan untuk membuktikan keaslian pengguna di sesi pengguna, dan menggunakan kembali backend sama untuk lamanya sesi tersebut bilamana mengakses ke pengguna dibuktikan keasliannya saat ini dibutuhkan. Ini secara efektif berarti bahwa sumber pembuktian keaslian disimpan pada per sesi, jadi jika anda merubah AUTHENTICATION_BACKENDS, anda akan butuh membersihkan data sesi jika anda butuh memaksa pengguna membuktikan keaslian kembali menggunakan model berbeda. Cara sederhana untuk melakukan itu adalah mengjalankan Session.objects.all().delete().

Menulis backend pembuktian keaslian

Sebuah backend pembuktian keaslian adalah sebuah kelas yang menerapkan dua cara dibutuhkan: get_user(user_id) dan authenticate(**credentials), dan juga kumpulan dari pilihan perizinan terhubung cara pembuktian keaslian.

Cara get_user mengambil user_id – yng dapat berupa nama pengguna, ID basisdata atau apapun, tetapi harus menjadu primary key dari obyek User anda – dan mengembalikan obyek User.

Cara authenticate mengambil mandat sebagai argumen kata kunci. Kebanyakan dari waktu, dia akan kelihatan seperti ini:

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

Tetapi itu dapat juga membuktikan keaslian sebuah token, seperti begitu:

class MyBackend(object):
    def authenticate(self, token=None):
        # Check the token and return a User.
        ...

Salah satu cara, authenticate harus memeriksa mandat yang dia dapatkan, dan dia harus mengembalikan obyek User yang cocok dengan mandat, jika mandat sah. Jika mereka tidak sah, dia harus mengembalikan None.

Admin Django erat ke Django Obyek User. Cara terbaik berurusan dengna ini adalah membuat obyek user Django untuk setiap pengguna yang ada untuk backend anda (sebagai contoh dalam direktori LDAP, basisdata SQL eksternal anda, dll.) Anda dapat salah satu menulis tulisan untuk melakukannya terlebih dahulu, atau cara authenticate anda dapat melakukannya pertama kali pengguna masuk.

Ini adalah sebuah contoh yang membuktikan keaslian variabel terhdap nama pengguna dan sandi ditentukan dalam berkas settings.py anda dan membuat sebuah obyek User Django pertama kali pengguna dibuktikan keaslian:

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

class SettingsBackend(object):
    """
    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, 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. Note that we can set password
                # to anything, because it won't be checked; the password
                # from settings.py will.
                user = User(username=username, password='get from settings.py')
                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

Menangani otorisasi dalam backend penyesuaian

Penyesuaian backend sah dapat menyediakan perizinan mereka sendiri.

Model pengguna akan mengutus perizinan fungsi pencaian (get_group_permissions(), get_all_permissions(), has_perm(), dan has_module_perms()) ke backend pembuktian keaslian apapun yang menerapkan fungsi ini.

The permissions given to the user will be the superset of all permissions returned by all backends. That is, Django grants a permission to a user that any one backend grants.

New in Django 1.8:

Jika backend memunculkan pengecualian PermissionDenied di has_perm() atau has_module_perms(), otorisasi akan segera gagal dan Django tidak akan memeriksa backend yang mengikutinya.

The simple backend above could implement permissions for the magic admin fairly simply:

class SettingsBackend(object):
    ...
    def has_perm(self, user_obj, perm, obj=None):
        if user_obj.username == settings.ADMIN_LOGIN:
            return True
        else:
            return False

Ini memberikan perizinan penuh kepada pengguna yang diberikan akses di contoh diatas. Perhatikan bahwa di penambahan ke argumen sama diberikan ke fungsi django.contrib.auth.models.User terkait, fungsi pembuktian keaslian backend semua mengambil obyek pengguna, yang mungkin menjadi pengguna anonim, sebagai sebuah argumen.

Penerapan otorisasi penuh dapat ditemukan dalam kelas ModelBackend di django/contrib/auth/backends.py, yang merupakan backend awal dan meminta tabel auth_permission kebanyakan waktu. Jika anda berharap untuk menyediakan kebiasaan penyesuaian untuk hanya bagian dari API backend, anda dapat mengambil keuntungan dari warisan Python dan subkelas ModelBackend dari menerapkan API lengkap di backend penyesuaian.

Otorisasi untuk pengguna anonim

Sebuah pengguna anonim adalah satu yang tidak dibuktikan keaslian yaitu mereka menyediakan rincian pembuktian keaslian yang tidak sah. Bagaimanapun, itu tidak dibutuhkan berarti mereka tidak diotorisasikan melakukan apapun. Pada kebanyakan tingkatan dasar, kebanyakan situs jaringan mengotorisasi pengguna anonim untuk menjelajahi kebanyakan situs, dan banyak mengizinkan pengguna memasang komentar dll.

Kerangka perizinan Django tidak mempunyai tempat untuk menyimpan perizinan untuk pengguna anonim. Bagaimanapun, obyek pengguna melewati backend pembuktian keaslian mungkin obyek django.contrib.auth.models.AnonymousUser, mengizinkan backend untuk menentukan kebiasaan otorisasi penyesuaian untuk pengguna anonim. Ini khususnya berguna untuk penulis dari aplikasi digunakan kembali, yang dapat menugaskan semua pertanyaan dan otorisasi ke backend pembuktian keaslian, daripada membutuhkan pengaturan, sebagai contoh, untuk mengendalikan akses anonim.

Otorisasi untuk pengguna tidak aktif

Sebuah pengguna tidak adalah adalah satu yang dibuktikan keaslian tetapi atributnya is_active disetel ke False. Bagaimanapun ini tidak berarti mereka tidak diotorisasi untuk melakukan apapun. Sebagai contoh mereka diizinkan untuk mengaktifkan akun mereka.

Dukungan untuk pengguna anonim di sistem perizinan mengizinkan untuk sebuah skenaria dimana pengguna anonim mempunyai perizinan untuk melakukan sesuatu selama pengguna dibuktikan keaslian tidak aktif tidak.

Jangan lupa untuk mencoba untuk atribut is_active dari pengguna di cara perizinan backend anda sendiri.

Penanganan perizinan obyek

Kerangka perizinan Django mempunyai sebuahyayasan untuk perizinan obyek, meskipun tidak ada penerapa untuknya didalam inti. Hal ini berarti bahwa memeriksa untuk perizinan obyek akan selalu mengembalikan False atau daftar kosong (tergantung pada penampilan pemeriksaan). Sebuah backend pembuktian keaslian akan menerima parameter katakunci obj dan user_obj untuk setiap obyek terkait cara otorisasi dan dapat mengembalikan tingkat perizinan obyek sewajarnya.

Penyesuaian perizinan

Untuk membuat perizinan penyesuaian untuk obyek model yang diberikan, gunakan permissions model Meta attribute.

Model task contoh ini membuat tiga perizinan penyesuaian, yaitu, tindakan pengguna dapat atau tidak dapat dilakukan dengan permintaan Task, khusus pada apliaksi anda:

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

Satu-satunya ini dilakukan adalah membuat perizinan tambahan ketika anda menjalankan manage.py migrate (fungsi yang membuat perizinan terhubung ke sinyal post_migrate). Kode anda bertanggung jawab dari pemeriksaan nilai perizinan ini ketika sebuah pengguna mencoba mengakses fungsionalitas disediakan oleh aplikasi (melihat tugas, merubah keadaan dari tugas, menutup tugas.) Melanjutkan contoh diatas, pemeriksaan berikut jika sebuah pengguna mungkin melihat tugas:

user.has_perm('app.view_task')

Memperpanjang model User yang ada

Terdapat dua jalan untuk memperpanjang model User awal tanpa mengganti model milik anda. Jika perubahan anda butuhkan murni kebiasaan, dan tidak membutuhkan perubahan apapun ke apa ang disimpan di basisdata, anda dapat membuat proxy model berdasarkan pada User. Ini mengizinkan fitur apapun ditawarkan oleh model proxy termasuk pemesanan awal, pengelola penyesuaian, atau cara model penyesuaian.

Jika anda berharap menyimpan informasi terkait ke User, anda dapat menggunakan OneToOneField pada sebuah model mengandung bidang untuk informasi tambahan. Ini model satu-ke-satu selalu memanggil model profil, karena dia akan menyimpan informasi terkait bukan-asli tentang pengguna situs. Sebagai contoh anda mungkin membuat sebuah model Employee:

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)

Mengganggap Pegawai Fred Smith yang ada yang mempunyai kedua model User dan Employee, anda dapat mengakses informasi terkait menggunakan standar Django ketentuan model terkait:

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

Untuk menambahkan profil bidang model ke halaman pengguna dalam admin, tentukan sebuah class:~django.contrib.admin.InlineModelAdmin (untuk contoh ini, kami akan menggunakan StackedInline) di admin.py aplikasi anda dan menambahkannya ke kelas UserAdmin yang terdaftar dengan kelas User:

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)

Model profil ini tidak khusus di jalan apapun - mereka hanya model Django yang terjadi untuk mempunyai kaitan satu-ke-satu dengan model User. Seperti, mereka tidak mendapatkan otomatis dibuat ketika pengguna dibuat, tetapi django.db.models.signals.post_save dapat digunakan untuk membuat atau memperbaharui model terkait sewajarnya.

Catat bahwa menggunakan hasil model terkait di tambahan permintaan atau penggabungan untuk mendapatkan data terkait, dan tergantung pada kebutuhan anda mengganti model User dan menambahkan bidang terkait mungkin pilihan terbaik anda. Bagaimanapun tautan terkait ke model User awal dalam aplikasi proyek anda mungkin membenarkan muatan basisdata lebih.

Mengganti model User penyesuaian

Beberapa macam proyek mungkin mempunyai persyaratan pembuktian keaslian untuk dimana model User dipasang tetap Django tidak selalu sesuai. Sebagai contoh, pada beberapa situs akan masuk akal menggunakan sebauh alamat surel sebagai token pencirian daripada nama pengguna.

Django mengizinkan anda untuk mengesampingkan model User awal dengan menyediakan nilai untuk pengaturan AUTH_USER_MODEL yang mengacu sebuah model penyesuaian:

AUTH_USER_MODEL = 'myapp.MyUser'

Pasangan titik ini menggambarkan nama dari aplikasi Django (yang harus berada di INSTALLED_APPS), dan nama dari model Django yang anda harapkan untuk digunakan sebagai model User anda.

Peringatan

Merubah AUTH_USER_MODEL mempunyai usaha besar di struktur basisdata anda. Dia merubah tabel yang tersedia, dan akan mempengaruhi susunan foreign key dan hubungan banyak-ke-banyak. Jika anda bermaksud menyetel AUTH_USER_MODEL, anda harus menyetelnya sebelum membuat perpindahan apapun atau menjalankan manage.py migrate untuk pertama kali.

Merubah pengaturan ini setelah anda mempunyai tabel dibuat tidak didukung oleh makemigrations dan akan menghasilkan anda secara manual memperbaiki skema anda, menghubungkan data anda dari tabel pengguna lama, dan mungkin secara manual memberlakukan kembali beberapa perpindahan.

Peringatan

Karena pembatasan dari fitur ketergantungan dinamis Django untuk model barter, anda harus memastikan bahwa model diacukan oleh AUTH_USER_MODEL dibuat di perpindahan pertama dari aplikasinya (biasanya dipanggil 0001_initial); sebaliknya, anda akan mempunyai masalah ketergantungan.

Sebagai tambahan, anda dapat menjalankan kedalam CircularDependencyError ketika menjalankan perpindahan anda sebagai Django tidak akan dapat otomatis memutus ketergantungan perulangan karena ketergantungan dinamis. Jika anda melihat kesalahan ini, anda harus memutus perulangan dengan memindahkan model tergantung pada model User anda kedalam perpindahan kedua (anda dapat mencoba membuat dua model biasa yang mempunyai ForeignKey satu sama lain dan melihat bagaimana makemigrations mengatasi ketergantungan perputaran jika anda ingin melihat bagaimana dia biasanya selesai)

Aplikasi digunakan kembali AUTH_USER_MODEL

Reusable apps shouldn’t implement a custom user model. A project may use many apps, and two reusable apps that implemented a custom user model couldn’t be used together. If you need to store per user information in your app, use a ForeignKey or OneToOneField to settings.AUTH_USER_MODEL as described below.

Mengacu model User

If you reference User directly (for example, by referring to it in a foreign key), your code will not work in projects where the AUTH_USER_MODEL setting has been changed to a different User model.

get_user_model()[sumber]

Instead of referring to User directly, you should reference the user model using django.contrib.auth.get_user_model(). This method will return the currently active User model – the custom User model if one is specified, or User otherwise.

Ketika anda menentukan foreign key atau hubungan many-to-many pada model User, anda harus menjelaskan penyesuaian model menggunakan pengaturan AUTH_USER_MODEL. Sebagai contoh:

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,
    )

Ketika terhubung ke sinyal yang dikirim oleh model User. anda harus menentukan penyesuaian model menggunakan pengaturan AUTH_USER_MODEL. Sebagai contoh:

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)

Secara umum, anda harus mengacu model User dengan pengaturan AUTH_USER_MODEL di kode yang dijalankan pada waktu impor. get_user_model() hanya bekerja sekali ketika Django telah mengimpor semua model.

Menentukan penyesuaian model User

Pertimbangan rancangan model

Berpikir hati-hati sebelum menangani informasi yang tidak langsung terkait pada pembuktian keaslian di penyesuaian Model User anda.

Itu mungkin lebih baik untuk menyimpan aplikasi-khusus informasi pengguna dalam sebuah model yang mempunyai hubungan dengan model User. Itu mengizinkan setiap aplikasi menentukan persyaratan data pengguna miliknya tanpa mempertaruhkan pertentangan dengan aplikasi lain. Di sisi lain, permintaan untuk mengambil informasi terkait ini akan melibatkan peggabungan basisdata, yang akan mempunyai pengaruh pada penampilan.

Django mengharapkan model User penyesuaian anda memenuhi persyaratan minimal.

  1. Jika anda menggunakan backend pembuktian keaslian awal, kemudian model anda harus mempunyai bidang unik tunggal yang dapat digunakan untuk tujuan pencirian. Ini dapat berupa nama pengguna, sebauh alamat surel, atau atribut unik lainnya. Bidang nama pengguna tidak unik diizinakn jika anda menggunakan penyesuaian backend pembuktian keaslian yang dapat mendukungnya.

  2. Model anda harus menyediakan cara terbaik utnuk mengalamatkan pengguna dalam bentuk “short” and “long”. Penafsiran paling umum dari ini akan digunakan nama diberikan pengguna sebagai penciri “short”, dan nama lengkap pengguna sebagai penciri “long”. Bagaimanapun, tidak ada batasan pada apa yang duca cara ini kembalikan - jika anda ingin, mereka dapat mengembalikan nilai sama yang tepat.

Changed in Django 1.8:

Versi lama dari Django membutuhkan model anda mempunyai primary key integer juga.

The easiest way to construct a compliant custom User model is to inherit from AbstractBaseUser. AbstractBaseUser provides the core implementation of a User model, including hashed passwords and tokenized password resets. You must then provide some key implementation details:

class models.CustomUser
USERNAME_FIELD

A string describing the name of the field on the User model that is used as the unique identifier. This will usually be a username of some kind, but it can also be an email address, or any other unique identifier. The field must be unique (i.e., have unique=True set in its definition), unless you use a custom authentication backend that can support non-unique usernames.

Dalam contoh berikut, bidang identifier digunakan sebagai bidang pengenal:

class MyUser(AbstractBaseUser):
    identifier = models.CharField(max_length=40, unique=True)
    ...
    USERNAME_FIELD = 'identifier'
New in Django 1.8.

USERNAME_FIELD now supports ForeignKeys. Since there is no way to pass model instances during the createsuperuser prompt, expect the user to enter the value of to_field value (the primary_key by default) of an existing instance.

REQUIRED_FIELDS

A list of the field names that will be prompted for when creating a user via the createsuperuser management command. The user will be prompted to supply a value for each of these fields. It must include any field for which blank is False or undefined and may include additional fields you want prompted for when a user is created interactively. REQUIRED_FIELDS has no effect in other parts of Django, like creating a user in the admin.

Sebagai contoh, ini adalah pengertian sebagian untuk model User yang menentukan dua bidang diwajibkan - tanggal dari kelahiran dan tinggi:

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

Catatan

REQUIRED_FIELDS harus mengandung semua bidang-bidang yang diwajibkan pada model User anda, tetapi harus tidak mengandung USERNAME_FIELD atau password ketika bidang-bidang ini akan selalu didorong.

New in Django 1.8.

REQUIRED_FIELDS now supports ForeignKeys. Since there is no way to pass model instances during the createsuperuser prompt, expect the user to enter the value of to_field value (the primary_key by default) of an existing instance.

is_active

A boolean attribute that indicates whether the user is considered “active”. This attribute is provided as an attribute on AbstractBaseUser defaulting to True. How you choose to implement it will depend on the details of your chosen auth backends. See the documentation of the is_active attribute on the built-in user model for details.

get_full_name()

A longer formal identifier for the user. A common interpretation would be the full name of the user, but it can be any string that identifies the user.

get_short_name()

A short, informal identifier for the user. A common interpretation would be the first name of the user, but it can be any string that identifies the user in an informal way. It may also return the same value as django.contrib.auth.models.User.get_full_name().

Mengimpor AbstractBaseUser

New in Django 1.9.

AbstractBaseUser and BaseUserManager are importable from django.contrib.auth.base_user so that they can be imported without including django.contrib.auth in INSTALLED_APPS (this raised a deprecation warning in older versions and is no longer supported in Django 1.9).

The following methods are available on any subclass of AbstractBaseUser:

class models.AbstractBaseUser
get_username()

Mengembalikan nilai dari bidang dicalonkan oleh USERNAME_FIELD.

is_anonymous()

Always returns False. This is a way of differentiating from AnonymousUser objects. Generally, you should prefer using is_authenticated() to this method.

is_authenticated()

Always returns True. This is a way to tell if the user has been authenticated. This does not imply any permissions, and doesn’t check if the user is active - it only indicates that the user has provided a valid username and password.

set_password(raw_password)

Sets the user’s password to the given raw string, taking care of the password hashing. Doesn’t save the AbstractBaseUser object.

When the raw_password is None, the password will be set to an unusable password, as if set_unusable_password() were used.

check_password(raw_password)

Returns True if the given raw string is the correct password for the user. (This takes care of the password hashing in making the comparison.)

set_unusable_password()

Marks the user as having no password set. This isn’t the same as having a blank string for a password. check_password() for this user will never return True. Doesn’t save the AbstractBaseUser object.

You may need this if authentication for your application takes place against an existing external source such as an LDAP directory.

has_usable_password()

Returns False if set_unusable_password() has been called for this user.

get_session_auth_hash()

Mengembalikan nilai HMAC dari kolom kata sandi. Digunakan untuk Session invalidation on password change.

You should also define a custom manager for your User model. If your User model defines username, email, is_staff, is_active, is_superuser, last_login, and date_joined fields the same as Django’s default User, you can just install Django’s UserManager; however, if your User model defines different fields, you will need to define a custom manager that extends BaseUserManager providing two additional methods:

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

The prototype of create_user() should accept the username field, plus all required fields as arguments. For example, if your user model uses email as the username field, and has date_of_birth as a required field, then create_user should be defined as:

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

The prototype of create_superuser() should accept the username field, plus all required fields as arguments. For example, if your user model uses email as the username field, and has date_of_birth as a required field, then create_superuser should be defined as:

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

Tidak seperti create_user(), create_superuser() harus membutuhkan pemanggil untuk menyedianan sebuah sandi.

BaseUserManager menyediakan cara kegunaan berikut:

class models.BaseUserManager
classmethod normalize_email(email)

Normalizes email addresses by lowercasing the domain portion of the email address.

get_by_natural_key(username)

Retrieves a user instance using the contents of the field nominated by USERNAME_FIELD.

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

Returns a random password with the given length and given string of allowed characters. Note that the default value of allowed_chars doesn’t contain letters that can cause user confusion, including:

  • i, l, I, and 1 (huruf kecil i, huruf kecil L, huruf besar i, dan angka satu)

  • o, O, and 0 (huruf kecil o, huruf besar o, dan nol)

Extending Django’s default User

If you’re entirely happy with Django’s User model and you just want to add some additional profile information, you could simply subclass django.contrib.auth.models.AbstractUser and add your custom profile fields, although we’d recommend a separate model as described in the “Model design considerations” note of Menentukan penyesuaian model User. AbstractUser provides the full implementation of the default User as an abstract model.

Custom users and the built-in auth forms

Django’s built-in forms and views make certain assumptions about the user model that they are working with.

Bentuk berikut cocok dengan subkelas apapun dari AbstractBaseUser:

The following forms make assumptions about the user model and can be used as-is if those assumptions are met:

  • PasswordResetForm: Assumes that the user model has a field named email that can be used to identify the user and a boolean field named is_active to prevent password resets for inactive users.

Finally, the following forms are tied to User and need to be rewritten or extended to work with a custom user model:

If your custom user model is a simple subclass of AbstractUser, then you can extend these forms in this manner:

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',)

Penyesuaian pengguna dan django.contrib.admin

If you want your custom User model to also work with Admin, your User model must define some additional attributes and methods. These methods allow the admin to control access of the User to admin content:

class models.CustomUser
is_staff

Mengembalikan True jika pengguna diizinkan mempunyai akses ke situs admin

is_active

Mengembalikan True jika akun pengguna saat ini aktif.

has_perm(perm, obj=None):

Returns True if the user has the named permission. If obj is provided, the permission needs to be checked against a specific object instance.

has_module_perms(app_label):

Mengembalikan True jika pengguna mempunyai perizinan untuk mengakses model pada aplikasi yang diberikan.

You will also need to register your custom User model with the admin. If your custom User model extends django.contrib.auth.models.AbstractUser, you can use Django’s existing django.contrib.auth.admin.UserAdmin class. However, if your User model extends AbstractBaseUser, you’ll need to define a custom ModelAdmin class. It may be possible to subclass the default django.contrib.auth.admin.UserAdmin; however, you’ll need to override any of the definitions that refer to fields on django.contrib.auth.models.AbstractUser that aren’t on your custom User class.

Penyesuaian pengguna dan perizinan

To make it easy to include Django’s permission framework into your own User class, Django provides PermissionsMixin. This is an abstract model you can include in the class hierarchy for your User model, giving you all the methods and database fields necessary to support Django’s permission model.

PermissionsMixin menyediakan cara dan atribut berikut:

class models.PermissionsMixin
is_superuser

Boolean. Designates that this user has all permissions without explicitly assigning them.

get_group_permissions(obj=None)

Returns a set of permission strings that the user has, through their groups.

If obj is passed in, only returns the group permissions for this specific object.

get_all_permissions(obj=None)

Returns a set of permission strings that the user has, both through group and user permissions.

If obj is passed in, only returns the permissions for this specific object.

has_perm(perm, obj=None)

Returns True if the user has the specified permission, where perm is in the format "<app label>.<permission codename>" (see permissions). If the user is inactive, this method will always return False.

If obj is passed in, this method won’t check for a permission for the model, but for this specific object.

has_perms(perm_list, obj=None)

Returns True if the user has each of the specified permissions, where each perm is in the format "<app label>.<permission codename>". If the user is inactive, this method will always return False.

If obj is passed in, this method won’t check for permissions for the model, but for the specific object.

has_module_perms(package_name)

Returns True if the user has any permissions in the given package (the Django app label). If the user is inactive, this method will always return False.

PermissionsMixin dan ModelBackend

If you don’t include the PermissionsMixin, you must ensure you don’t invoke the permissions methods on ModelBackend. ModelBackend assumes that certain fields are available on your user model. If your User model doesn’t provide those fields, you will receive database errors when you check permissions.

Custom users and proxy models

One limitation of custom User models is that installing a custom User model will break any proxy model extending User. Proxy models must be based on a concrete base class; by defining a custom User model, you remove the ability of Django to reliably identify the base class.

If your project uses proxy models, you must either modify the proxy to extend the User model that is currently in use in your project, or merge your proxy’s behavior into your User subclass.

Sebuah contoh penuh

Here is an example of an admin-compliant custom user app. This user model uses an email address as the username, and has a required date of birth; it provides no permission checking, beyond a simple admin flag on the user account. This model would be compatible with all the built-in auth forms and views, except for the User creation forms. This example illustrates how most of the components work together, but is not intended to be copied directly into projects for production use.

This code would all live in a models.py file for a custom authentication app:

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):
        """
        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 get_full_name(self):
        # The user is identified by their email address
        return self.email

    def get_short_name(self):
        # The user is identified by their email address
        return self.email

    def __str__(self):              # __unicode__ on Python 2
        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

Then, to register this custom User model with Django’s admin, the following code would be required in the app’s admin.py file:

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 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 forms.ValidationError("Passwords don't match")
        return password2

    def save(self, commit=True):
        # Save the provided password in hashed format
        user = super(UserCreationForm, self).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
    password hash display field.
    """
    password = ReadOnlyPasswordHashField()

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

    def clean_password(self):
        # Regardless of what the user provides, return the initial value.
        # This is done here, rather than on the field, because the
        # field does not have access to the initial value
        return self.initial["password"]


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)

Finally, specify the custom model as the default user model for your project using the AUTH_USER_MODEL setting in your settings.py:

AUTH_USER_MODEL = 'customauth.MyUser'