Personalizando a autenticação no DjangoLink para este cabeçalho
A autenticação que vem com o Django é boa o suficiente pros casos mais comuns, mas você pode ter necessidades que não atendem os padrões fora-da-caixa. Para customizar a autenticação de forma a atender as necessidades do seu projeto, é preciso entender quais pontos do sistema fornecido são extensíveis ou substituíveis. Esse documento fornece detalhes sobre como o sistema de autenticação pode ser customizado.
Autenticação backend provê um sistema extensível para quando o username ou senha armazenado no User model precisar ser autenticado em um diferente serviço que o Django tem por padrão.
Você pode dar para seus models permissões customizadas que pode ser conferidas através do sistema de autorização do Django.
Você pode extender o User model padrão, ou substituir por um model completamente customizado.
Outras fontes de autenticaçãoLink para este cabeçalho
Pode haver várias vezes que você precise enganchar em outro código de autenticação, outro código de usuário ou senha ou métodos de autenticação.
Por exemplo, sua companhia pode já ter um LDAP configurado que armazena o usuário e a senha para cada empregado. Isto é um aborrecimento para ambos administradores de rede e os próprios usuários se os usuários tiverem contas separadas em LDAP e a aplicação baseada em Django.
Então, para lidar com situações como está, o sistema de autenticação do Django deixa você conectá-lo em outras fontes de autenticação. Você pode sobrescrever o esquema padrão baseado em banco de dados, ou você pode usar o sistema padrão em conjunto com outros sistemas.
Veja a referência do backend de autenticação para informação sobre backends de autenticação incluída com Django.
Especificando backends de autenticaçãoLink para este cabeçalho
Por de trás dos panos, Django mantém uma lista de “backends de autenticação” que ele verifica para autenticação. Quando alguém chama: func:django.contrib.auth.authenticate() – como descrito em Como logar um usuário – Django tenta autenticar através de todas os backends de autenticações. Se o primeiro método falhar, Django tenta o segundo, e assim por diante, até todos os backends terem sido tentados.
A lista de backends autenticação usada é especificada na definição AUTHENTICATION_BACKENDS. Isto deve ser uma lista de nomes de caminhos Python que apontam para classes Python que sabem como autenticar. Essas classes podem estar em qualquer lugar no seu caminho Python (python path).
Por padrão, :settings:`AUTHENTICATION_BACKENDS` é definido como:
['django.contrib.auth.backends.ModelBackend']
Esta é o “backend” de autenticação básico que verifica o banco de dados de usuários Django e consulta as suas permissões embutidas. Ele não provê proteção contra ataques de força bruta via qualquer mecanismo limitante. Você pode implementar seu próprio mecanismo com taxa de limitação em um “backend” customizado de autenticação, ou usar o mecanismo fornecido pela maioria dos servidores Web.
A ordem dos :settings:`AUTHENTICATION_BACKENDS` importa, então se o mesmo usuário e senha são válidos em múltiplos backends, Django vai parar de processar na primeira combinação positiva.
Se um “backends” emitir uma exceção PermissionDenied, a autenticação irá falhar imediatamente. Django não irá verificar os próximos “backends”.
Desenvolvendo um backend de autenticaçãoLink para este cabeçalho
Um “backend” de autenticação é uma classe que implementa 2 métodos obrigatórios: get_user(user_id) e authenticate(**credentials), também um conjunto de permissões opcionais relacionadas métodos de autorização.
O método get_user recebe um user_id – o qual pode ser um nome de usuário, id do banco de dados, tanto faz, mas tem que ser a chave-primária do seu objeto User – e retorna um objeto User.
O método recebe credenciais como argumentos nomeados. Na maioria das vezes, isso deve parecer com isso:
class MyBackend(object):
def authenticate(self, username=None, password=None):
# Check the username/password and return a User.
...
Mas ele poderia também autenticar um token, tal qual:
class MyBackend(object):
def authenticate(self, token=None):
# Check the token and return a User.
...
de qualquer maneira, o authenticate deve verificar as credenciais que recebe, e deve retornar um objeto User que combine com as credenciais, se as credenciais forem válidas. Se elas não são válidas, ele deve retornar None.
O Django admin está bem casado com o objeto User do Django. A melhor maneira de lidar com isso é criar um objeto User do Django para cada usuário que existir para seu “backend” (por ex.:, no seu diretório LDAP, seu banco de dados SQL externo e etc) Você pode inclusive escrever um script para fazer isso de ante-mão, ou seu método de autenticação pode fazê-lo na primeira vez que o usuário se logar.
Aqui um exemplo de “backend” que autentica com um nome de usuário e senha variáveis definidas no seu arquivo settings.py e cria um User Django na primeira vez que um usuário se autentique:
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
Permissões personalizadasLink para este cabeçalho
Para criar permissões persaonalizadas para um dado objeto de modelo, use o permissions model Meta attribute.
Este modelos “Task” de exemplo cria três permissões personalizadas, isto é, ações que usuários podem ou não podem fazer com instâncias de “Tasks”, específicas para sua aplicação:
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"),
)
A única coisa que isso faz é criar aquelas permissões extras quando você roda manage.py migrate ( a função que cria permissões está conectada com o sinal post_migrate). Seu código está encarregado de verificar o valor destas permissões quando um usuário está tentando acessar a funcionalidade fornecida pela aplicação (ver tarefas, edita o status de tarefas, fechar tarefas). Continuando o exemplo acima, as seguintes verificam se um usuário pode ver “Tasks”:
user.has_perm('app.view_task')
Estendendo o modelo Usuário existenteLink para este cabeçalho
Existem duas maneiras de estender o modelo padrão User sem substituir seu próprio modelo. Se as mnudanças que precisa são puramente comprtamentais, e nao requerem nenhuma mudança no que é armazenado no banco de dados, você pode criar um proxy model baseado na User. Isso permite qualquer das funcionalidades oferecidas pelo modelo “proxy” incluindo “ordering” padrão, “managers” personalizados ou métodos persononalizados do modelo.
Se você deseja armazenar informação relacionada ao User, você pode usar a OneToOneField para um modelo contento os campos para a informação adicional. Este modelo com relação um-pra-um é muitas vezes chamado modelo de perfil, uma vez que poderia armazenar infomração que nao está relacionada com autenticação sobre o usuário do site. Por exemplo você poderia criar um modelo “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)
Assumindo um “Employee” existente Fred Smith o qual tem ambos os modelos “User” e “Employee”, você pode acessar a informação relacionada usando a convenção de relação de modelo padrão do Django.
>>> u = User.objects.get(username='fsmith')
>>> freds_department = u.employee.department
Para adicionar os campos do modelo de perfil para uma página de usuário no admin, defina uma InlineModelAdmin (para este exemplo, iremos usar uma StackedInline) no admin.py da sua aplicação e a adicione a classe UserAdmin a qual é registrada com a classe 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)
Este modelo de perfil não é especial de nenhum modo - eles são somente modelos Django que tem uma relação de um-pra-um com o modelo User. Portanto, eles não são criados automaticamente quando um usuário é criado, mas um django.db.models.signals.post_save pode ser usado para criar ou editar modelos relacionados quando apropriado.
Note que usar modelos relacionados resultam em consultas ou “joins” adicionais para retornar os dados relacionados, e dependendo de suas necessidades substituindo o modelo User e adicionando os campos relacionados talvez seja uma opção melhor. Todavia conexões existentes para o modelo de usuário padrão dentro da aplicação do seu projeto talvez justifique a carga extra no banco de dados.
Substituindo um modelo de Usuário personalizadoLink para este cabeçalho
Alguns tipos de projetos talvez tenham requerimentos de autenticação para as quais o modelo User embutido do Django nem sempre é apropriado. Por exemplo, em alguns sites tenha mais sentido usar um endereço de e-mail como seu “token” de identificação no lugar de um nome de usuáro.
O Django permite que você sobrescreva o modelo “User” padrão através da definição de um valor para AUTH_USER_MODEL que referencia um modelo personalizado:
AUTH_USER_MODEL = 'myapp.MyUser'
Este par pontuado descreve o nome da aplicação Django (o qual deve estar no seu INSTALLED_APPS), e o nome do modelo Django que você deseja usar como seu modelo de usuário.
Referenciando o modelo UsuárioLink para este cabeçalho
Se você referencia diretamente o User (fpor exemplo, fazendo uma referencia através de uma chave estrangeira), seu código não irá funcionar em projetos onde a definição do AUTH_USER_MODEL tenha sido mudada para um modelo de “User” diferente.
- get_user_model()Link para esta definição
Ao invés de referenciar diretamente a
User, você deve referenciar o modelo usando odjango.contrib.auth.get_user_model(). Este método irá retornar o modelo de usuário atualmente ativo – O modelo de usuário personalizado se for especificado, ou se não oUser.QUando você definie uma chave estrangeira ou relações muitos-para-muitos para o modelo de usuário, você deve especificar o modelo usando a definição
AUTH_USER_MODEL. Por exemplo: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, )Quando conectar com “signals” enviados pelo modelo
User, você deve especificar o modelo personalizado usando a definição doAUTH_USER_MODEL. Por exemplo: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)Falando genericamente, você deve referenciar o modelo de usuário com a definição do
AUTH_USER_MODELem código que é executado em tempo de importação. Oget_user_model()somente funciona uma vez que o Django tenha importado todos os modelos.
Especificando um modelo User personalizadoLink para este cabeçalho
O Django espera que seu modelo de usuário personalizado garanta algumas caracetrísticas mínimas.
Se você usa o “backend” padrão de autenticação, então seu modelo deve ter um único campo “unique” que possa ser usado com o propósito de identificação. Isso pode ser um nome de usuário, um endereço de e-mail, ou qualquer atributo “unique”. Um nome de usuário que permita duplicaidade é permitido se você usar um “backend” de autenticação que dê suporte a isso.
Seu modelo deve fornecer um maneira de endereçar o usuário de uma forma “curta” e outra “longa”. A interpretação mais comum disso seria usar o nome do usuário como identificador “curto”, e o nome completo do usuário como identificador “longo”. Porém, não tem nenhuma regra quanto ao o que estes dois métodos retornam – Se você quiser, eles podem retornar exatamente o mesmo valor.
A maneira mais fácil de construir um modelo de usuário compatível é herdar da AbstractBaseUser. A AbstractBaseUser fornece a implementação principal de um modelo ``User`, incluindo senhas criptografadas e “tokes” para resetar senhas. Você deve então fornecer algumas detalhes de implementações chave.
- class models.CustomUserLink para esta definição
- USERNAME_FIELDLink para esta definição
Uma string descrevendo o nome do campo no modelo do usuário que é usado como identificador único. Isso será geralmente o nome do usuário de algua maneira, mas pode ser também um endereço de e-mai, ou qualquer outro identificador único. O campo deve ser único (isto é, ter ``unique=True``definido na sua definição), a menos que você use um “backend” de autenticação personalizado que possa dar suporte a nomes de usuário com duplicidade.
No exemplo seguinte, o campo
identifieré usado como o campo identificador:class MyUser(AbstractBaseUser): identifier = models.CharField(max_length=40, unique=True) ... USERNAME_FIELD = 'identifier'USERNAME_FIELDagora suportaForeignKeys. Uma vez que nao tem como passar uma instancia de modelo durante o “prompt”createsuperuser, espera que usuário entre com o valor doto_field(oprimary_keypor padrão) de uma instância existente.
- REQUIRED_FIELDSLink para esta definição
Um lista de nomes de campos que serão demandados quando criar um usuário através do coando de gerenciamento
createsuperuser. O usuário será demandado a fornecer um valor para cada um destes campos. Isso deve incluir qualquer campo para o qual oblankéFalseou indefinido e pode incluir campos adicionais que você queira demandar quando o usuário for criado interativamente. OREQUIRED_FIELDSnão tem efeito em outras partes do Django, como criar um usuario no admin.Por exemplo, aqui é a definição parcial de um modelo de
Userque define dois campos requeridos - um “date of birth” e “height”:class MyUser(AbstractBaseUser): ... date_of_birth = models.DateField() height = models.FloatField() ... REQUIRED_FIELDS = ['date_of_birth', 'height']USERNAME_FIELDagora suportaForeignKeys. Uma vez que não tem como passar uma instância de modelo durante o “prompt”createsuperuser, espera que usuário entre com o valor doto_field(oprimary_keypor padrão) de uma instância existente.
- is_activeLink para esta definição
Um atributo booleano que indica se o usuário é considerado “active”. Este atributo é fornecido como um atributo na
AbstractBaseUserpadronizado omoTrue. Como você escolhe como implementar isso irá depender dos detalhes do seu “backend” de autenticação escolhido. Veja a documentação doo atributo "is_active" do modelo de usuário embutidopara detalhes.
- get_full_name()Link para esta definição
Um identificador formal logon para o usuário. Uma interpretação comum seria o nome completo do usuário, mas pode ser qualquer string que identifique o usuário.
- get_short_name()Link para esta definição
Um identificação informal curta do usuário. Um interpretação comum seria o peimeiro nome do usuário, mas pode ser qualquer string que identifique o usuário de forma informal. Também pode retornar o mesmo valor que
django.contrib.auth.models.User.get_full_name().
Os seguintes métodos estão disponíveis em qualquer subclasse de AbstractBaseUser:
- class models.AbstractBaseUserLink para esta definição
- get_username()Link para esta definição
Retorna o valor do campo denominado no
USERNAME_FIELD.
- is_anonymous()Link para esta definição
Sempre retorna
False. Essa é uma maneira de diferenciar dos objetos do tipoAnonymousUser. Geralmente, você deve preferir usaris_authenticated()para este método.
- is_authenticated()Link para esta definição
Sempre retorna
True. Esta é uma maneira de dizer se o usuário foi autenticado. Isso não implica em nenhuma permissão, e não verifica se o usuário é ativo - isso somente indica se o usuário forneceu um nome de usuário e senha válidos.
- set_password(raw_password)Link para esta definição
Define a senha do usuário para uma dada string simples, levando em conta a criptografia da senha. Não salva o objeto
AbstractBaseUser.Quando a senha simples (plana) é
None, a senha será definida como uma senha inutilizável, como seset_unusable_password()fosse usado.
- check_password(raw_password)Link para esta definição
Retorna ``True``se a string simples é a senha correta para o usuário. (leva em conta a criptografia da senha quando fizer a comparação.)
- set_unusable_password()Link para esta definição
Marca o usuário como não tendo uma senha definida. Não é o mesmo que uma string em branco para senha.
check_password()para este usuário nunca retornaráTrue. Não salva o objetoAbstractBaseUser.Você talvez precise disso se a autenticação para sua aplicação é feita em uma fonte externa existente como um diretório LDAP.
- has_usable_password()Link para esta definição
Retorna
Falseseset_unusable_password()foi chamado para este usuário.
- get_session_auth_hash()Link para esta definição
Retorna um HMAC do campo senha. Usado para “Session invalidation on password change” isto é, invalidar sessão no caso de alteração de password.
Você deve também definir um “manager” personalizado para seu modelo User. Se seu modelo User defini os campos username, email, is_staff, is_active, is_superuser, last_login, e date_joined o mesmo que o User padrão do Django, você pode somente instalar o UserManager; Porém, se seu modelo User define campos diferentes, você precisa definir um “manager” personalizado que estende BaseUserManager e fornecendo dois métodos adicionais.
- class models.CustomUserManagerLink para esta definição
- create_user(*username_field*, password=None, \**other_fields)Link para esta definição
O protótipo de
create_user()``deve aceitar o campo "username" , mais todos os campos requeridos como argumentos. Por exemlo, se seu modelo de usuário usa ``emailcomo o campo username, e temdate_of_birthcomo campo requerido, entãocreate_userdeve ser definido como:def create_user(self, email, date_of_birth, password=None): # create user here ...
- create_superuser(*username_field*, password, \**other_fields)Link para esta definição
O protótipo de
create_superuser()``deve aceitar o campo "username" , mais todos os campos requeridos como argumentos. Por exemlo, se seu modelo de usuário usa ``emailcomo o campo “username”, e temdate_of_birthcomo campo requerido, entãocreate_userdeve ser definido como:def create_superuser(self, email, date_of_birth, password): # create superuser here ...Diferente de
create_user(), ocreate_superuser()deve requerer o “caller” para fornecer um password.
BaseUserManager fornece os seguintes métodos de utilidade:
- class models.BaseUserManagerLink para esta definição
- classmethod normalize_email(email)Link para esta definição
Normalizes email addresses by lowercasing the domain portion of the email address.
- get_by_natural_key(username)Link para esta definição
Retornar uma instância de usuário usando o conteúdo do campo denominado no
USERNAME_FIELD.
- make_random_password(length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789')Link para esta definição
Retorna uma senha randômica com o tamanho dado e a dada string de caracteres permitidos. Note que o calor padrão de
allowed_charsnão contém letrar que podem causar confusão, incluindo:i,l,I, e1(letra i minúscula, letra L maiúscula, letra i maiúscula, e o número um)o,O, e0(letra o minúscula, letra o maiúscula, e zero)
Estendendo o Usuário padrão do DjangoLink para este cabeçalho
Se você está inteiramente feliz com o modelo User do Django e você só quer adicionar algumas infomrações de perfil, você pode simplesmente criar uma subclasse de django.contrib.auth.models.AbstractUser e adicionar seus campos de perfil customizados, embora recomendaríamos um modelo separado como descrito no “Considerações de design de modelo” note o Especificando um modelo User personalizado. O AbstractUser fornece uma implementação completa da User padrão como um modelo abstrato.
Usuários personalizados e o formulários de autenticação embutidos.Link para este cabeçalho
Os forms e views embutidos no Django tem certas premissas sobre o modelo de usuário que eles estão trabalhando.
Os “forms” seguintes são compatíveis com qualquer subclasse de AbstractBaseUser:
A
AuthenticationForm: usa o campo username especificado peloUSERNAME_FIELD.
Os seguintes forms tem premissas sobre o modelo de usuário e podem ser usadas como estão se estas premissas forem atendidas:
PasswordResetForm: assume que o modelo de usuário tem um campo chamadoemailque pode ser usado para identificar o usuário e um campo booleano chamadois_activepara prevenir o “reset” de senhas por usuários inativos.
Finalmente, os seguintes forms estão amarrados a User e precisa ser rescrito ou estendido para funcionar com o modelo de usuário personalizado:
Se o seu modelo de usuário personalizado é uma simples subclasse de AbstractUser, então você pode estender estes forms desta manera:
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',)
Usuários personalizados e django.contrib.adminLink para este cabeçalho
Se você quer que seu modelo de usuário personalizado também trabalhe com o Admin, se modelo de usuário deve definir alguns atributos adicionais e métodos. Estes métodos possibilitam o admin a controlar o acesso do usuário ao conteúdo do admin:
- class models.CustomUserLink para esta definição
- is_staffLink para esta definição
Retorna ``True``se o usuário está permitido a ter acesso ao site admin.
- is_activeLink para esta definição
Retorna
Truese a conta de usuário estiver ativa.
- has_perm(perm, obj=None):
Retorna
True``se o usuário tem a permissão nominada. Se ``objé fornecido, a permissão necessária para ser verificado para uma instância de objeto específica.
- has_module_perms(app_label):
Retorna ``True``se o usuário tem permissão para acessar modelos na dada aplicação.
Você irá também precisar registrar seu modelo de usuário personalizado com o admin. Se o seu modelo de usuário customizado estende django.contrib.auth.models.AbstractUser, você pode usar a classe existente django.contrib.auth.admin.UserAdmin do Django. Porém, se o seu modelo de usuário estende AbstractBaseUser, você irá precisar definir uma classe ModelAdmin personalizada. Talvez seja possível criar uma subclasse da django.contrib.auth.admin.UserAdmin padrão; Porém, você irá precisar sobrescrever qualquer definição que referencie campos na django.contrib.auth.models.AbstractUser que não estão na sua classe de usuário personalizada.
Usuários personalizados e permissõesLink para este cabeçalho
Para tornar fácil incluir o framework de permissões do Django na sua própria classe User, Django fornece PermissionsMixin. Isso é um modelo abstrato que você pode incluir na hierarquia de classe para seu modelos de usuário, dando a você todos os métodos e campos do banco de dados necessários para dar suporte ao modelo de permissões do Django.
PermissionsMixin fornece os seguintes métodos e atributos:
- class models.PermissionsMixinLink para esta definição
- is_superuserLink para esta definição
Booleano. Designa que este user tem todas as permissões sem assinalá-las explicitamente.
- get_group_permissions(obj=None)Link para esta definição
Retorna um conjunto de strings de permissões que o usuário tem através de seus grupos.
Se o
objé passado, somente retorna o grupo de permissões para este objeto específico.
- get_all_permissions(obj=None)Link para esta definição
Retorna um conjunto de strings de permissões que o usuário tem, através de ambos permissões de grupo e usuário.
Se o
objé passado, somente retorna as permissões para este objeto específico.
- has_perm(perm, obj=None)Link para esta definição
Retorna
Truese o usuário tem a permissão especificada, ondepermestá no formato"<app label>.<permission codename>"(see permissões). Se o usuário é inativo, este método irá sempre retornarFalse.Se
objé passado, este método não irá verificar por permissões para o modelo, mas para este objeto específico.
- has_perms(perm_list, obj=None)Link para esta definição
Retorna
Truese o usuário tem cada uma das permissões especificadas, onde cara permissão este no formato"<app label>.<permission codename>". Se o usuário é inativo, este método sempre irá retornarFalse.Se
objé passado, este método não irá verificar por permissões para o modelo, mas para este objeto específico.
- has_module_perms(package_name)Link para esta definição
Retorna
Truese o usuário tiver qualquer permissão no dado pacote (o nome da aplicação Django). Se o usuário é inativo, este métodos irá sempre retornarFalse.
PermissionsMixin e ModelBackend
Se você não incluir o PermissionsMixin, você deve se assegurar de não invocar os métodos de permissões no ModelBackend. O ModelBackend assume que certos campos estão disponíveis no sei modelos de usuário. Se o seu modelos User não fornece estes campos, você irá receber um erro de banco de dados quando você veriricar as permissões.
Usuários personalizados e modelos de proxyLink para este cabeçalho
Uma limitação de modelos de usuários personalizados é que ao instalar um modelos de usuário personalizado irá quebrar qualquer modelos “proxy” que estenda User. Modelos “proxy” devem ser baseados em um classe concreta; definindo um modelo de usuário personalizado, você remove a habilidade do Django de identificar com segurança a classe base.
Se seu projeto usa modelos “proxy”, você deve ou modificar o “proxy” para estender o modelos de usuário que está em uso no seu projeto, ou juntar o comportamento do seu modelo “proxy” na sua subclasse de usuário.
Um exemplo completoLink para este cabeçalho
Aqui está um exemplo de uma aplicação de usuário customizada compatível com o admin. Este “user model” utiliza um endereço de e-mail como nome de usuário e requer uma data de nascimento; realiza verificação de permissões, além de uma simples administração de contas de usuários. Este model é compatível com todos forms de autenticação “auth forms” e views embutidos, exceto para os forms de criação de usuários “User creation forms”. Este exemplo ilustra como a maioria dos componentes funcionam juntos, mas não se destina a ser copiado e aplicado diretamente nos projetos para uso em produção.
Todo este código deve estar no arquivo “models.py” para um aplicativo de autenticação customizável:
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
Então, para registrar este aplicativo customizado e ser possível acessá-lo por meio do admin do Django, o seguinte código deve ser inserido no arquivo “admin.py” da aplicação.
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)
Finalmente, especifique o model customizado como sendo o “user model” padrão para o seu projeto, utilizando para isso, AUTH_USER_MODEL no arquivo “settings.py”:
AUTH_USER_MODEL = 'customauth.MyUser'