1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
|
"""
This module allows importing AbstractBaseUser even when django.contrib.auth is
not in INSTALLED_APPS.
"""
import unicodedata
from django.conf import settings
from django.contrib.auth import password_validation
from django.contrib.auth.hashers import (
acheck_password,
check_password,
is_password_usable,
make_password,
)
from django.db import models
from django.utils.crypto import salted_hmac
from django.utils.translation import gettext_lazy as _
class BaseUserManager(models.Manager):
@classmethod
def normalize_email(cls, email):
"""
Normalize the email address by lowercasing the domain part of it.
"""
email = email or ""
try:
email_name, domain_part = email.strip().rsplit("@", 1)
except ValueError:
pass
else:
email = email_name + "@" + domain_part.lower()
return email
def get_by_natural_key(self, username):
return self.get(**{self.model.USERNAME_FIELD: username})
async def aget_by_natural_key(self, username):
return await self.aget(**{self.model.USERNAME_FIELD: username})
class AbstractBaseUser(models.Model):
password = models.CharField(_("password"), max_length=128)
last_login = models.DateTimeField(_("last login"), blank=True, null=True)
is_active = True
REQUIRED_FIELDS = []
# Stores the raw password if set_password() is called so that it can
# be passed to password_changed() after the model is saved.
_password = None
class Meta:
abstract = True
def __str__(self):
return self.get_username()
# RemovedInDjango60Warning: When the deprecation ends, replace with:
# def save(self, **kwargs):
# super().save(**kwargs)
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
if self._password is not None:
password_validation.password_changed(self._password, self)
self._password = None
def get_username(self):
"""Return the username for this User."""
return getattr(self, self.USERNAME_FIELD)
def clean(self):
setattr(self, self.USERNAME_FIELD, self.normalize_username(self.get_username()))
def natural_key(self):
return (self.get_username(),)
@property
def is_anonymous(self):
"""
Always return False. This is a way of comparing User objects to
anonymous users.
"""
return False
@property
def is_authenticated(self):
"""
Always return True. This is a way to tell if the user has been
authenticated in templates.
"""
return True
def set_password(self, raw_password):
self.password = make_password(raw_password)
self._password = raw_password
def check_password(self, raw_password):
"""
Return a boolean of whether the raw_password was correct. Handles
hashing formats behind the scenes.
"""
def setter(raw_password):
self.set_password(raw_password)
# Password hash upgrades shouldn't be considered password changes.
self._password = None
self.save(update_fields=["password"])
return check_password(raw_password, self.password, setter)
async def acheck_password(self, raw_password):
"""See check_password()."""
async def setter(raw_password):
self.set_password(raw_password)
# Password hash upgrades shouldn't be considered password changes.
self._password = None
await self.asave(update_fields=["password"])
return await acheck_password(raw_password, self.password, setter)
def set_unusable_password(self):
# Set a value that will never be a valid hash
self.password = make_password(None)
def has_usable_password(self):
"""
Return False if set_unusable_password() has been called for this user.
"""
return is_password_usable(self.password)
def get_session_auth_hash(self):
"""
Return an HMAC of the password field.
"""
return self._get_session_auth_hash()
def get_session_auth_fallback_hash(self):
for fallback_secret in settings.SECRET_KEY_FALLBACKS:
yield self._get_session_auth_hash(secret=fallback_secret)
def _get_session_auth_hash(self, secret=None):
key_salt = "django.contrib.auth.models.AbstractBaseUser.get_session_auth_hash"
return salted_hmac(
key_salt,
self.password,
secret=secret,
algorithm="sha256",
).hexdigest()
@classmethod
def get_email_field_name(cls):
try:
return cls.EMAIL_FIELD
except AttributeError:
return "email"
@classmethod
def normalize_username(cls, username):
return (
unicodedata.normalize("NFKC", username)
if isinstance(username, str)
else username
)
|