Personalizando a autenticação no Django¶
A autenticação que vem com o Django é suficiente para os casos mais comuns, mas você pode ter necessidades que não são atendidas pelas configurações padrão. Para personalizar a autenticação de forma a atender as necessidades do seu projeto, é preciso entender quais pontos do sistema são extensíveis ou substituíveis. Esse documento fornece detalhes sobre como o sistema de autenticação pode ser personalizado.
Authentication backends fornece um sistema extensível para quando um nome de usuário e uma senha, armazenados com o modelo de usuário, precisam ser autenticados contra um serviço diferente do padrão do Django.
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 modelo User
padrão, ou substituir por um modelo completamente personalizado.
Outras fontes de autenticação¶
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ção¶
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”.
Nota
Uma vez que um usuário esteja autenticado, Django armazena qual o “backend” foi usado para autenticar aquele usuário na sessão do usuário, e re-usa o mesmo backend pela duração da sessão sempre que o acesso ao usuário autenticado atualmente for necessário. Isto efetivamente significa que as fontes de autenticação são cacheadas baseada por sessão, então se você mudar :setting`AUTHENTICATION_BACKENDS`, você irá precisar limpar os dados da sessão se você precisar forçar o usuário a re-autenticar usando diferentes métodos. Uma maneira simples de fazer isto é executar Session.objects.all().delete()
.
Desenvolvendo um backend de autenticação¶
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 “username”, ID do banco de dados ou qualquer outra coisa, contanto que seja a chave-primária do seu objeto “user” – e que retorne um objeto do tipo “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.
...
Da mesma maneira, o authenticate()
deve verificar as credenciais que recebeu e retornar um objeto do tipo “user” que combine com aquelas credenciais se estas forem válidas. Se as credenciais não forem 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. 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
Lidando com autorização em bakends personalizados¶
Backends de autenticação customizados podem fornecer suas próprias permissões
O modelo de usuário irá delegar funções “lookup” de permissões (get_group_permissions()
, get_all_permissions()
, has_perm()
, and has_module_perms()
) para qualquer “backend” de autenticação que implemente essas funções.
As permissões dadas para o usuário será um super-conjunto de todas as permissões devolvidas de todos os back-ends . Ou seja , o Django concede uma permissão para um usuário que qualquer backend concederia.
Se um “backend” emiti uma exceção PermissionDenied
no has_perm()
ou has_module_perms()
, a autorizaçõ irá falhar imediatamente e o Django não irá verificar os próximos “backends”.
O “backend” simples acima poderia implementar permissões para o mágico admin de maneira relativamente simples.
class SettingsBackend(object):
...
def has_perm(self, user_obj, perm, obj=None):
return user_obj.username == settings.ADMIN_LOGIN
Isso dá permissão total para o usuário para qual o acesso foi concedido no exemplo acima. Note que além dos mesmos argumentos dados as funções associadas ao usuário, todas as funções do “backend” de autenticação recebem o objeto user, o qual talvez seja um usuário anônimo, como argumento.
Uma implementação completa de autorização pode ser encontrada na classe ModelBackend
no django/contrib/auth/backends.py, o qual é o “backend” padrão e consulta a tabela auth_permission
na maior parte do tempo. Se você quer fornecer um comportamento personalizado para somente parte da API do “backend”, você pode tirar vantagem da herança Python e criar uma subclasse de ModelBackend
ao invés de de implmentar a API completa em um “backend” customizado.
Autorização para usuários anônimos¶
Um usuário anônimo é um que não está autenticado poe exemplo ele forneceu detalhes de autenticação não válidos. Todavia, isso não quer dizer necessariamente que eles não estão autorizados a fazer nada. Em um nível mais básico, a maioria dos websites autorizam usuário anônimos a navegar a maior parte do site, e muitos permitem enviar comentários e etc.
O framework de permissão do Django não possui um local para armazenar permissões para usuários anônimos. Porém, o objeto usuário passado para um “backend” de autenticação pode ser um objeto django.contrib.auth.models.AnonymousUser
, permitindo o “backend” a especificar um comportamento de autorização personalizado para usuários anônimos. Isso é especialmente útil para autores de “apps” reutilizáveis, que podem delegar todas as questões de autorização para o “backend” de autorização, ao invés de demandar configurações, por exemplo, controlar acesso de anônimos.
Autorização para usuários inativos¶
Um “user” inativo é o aquele que tem seu campo is_active
definido como False
. Os backends de autenticação ModelBackend
e RemoteUserBackend
não permitem que este usuário se autentique. Se um modelo personalizado de “user” não tem o is_active
, todos os usuários serão permitidos a se autenticar.
Você pode usar a AllowAllUsersModelBackend
ou AllowAllUsersRemoteUserBackend
se quiser que usuários inativos se autentiquem.
O suporte para usuários anônimos no sistema de permissão permite um cenário onde usuários anônimos tem permissões de fazer alguma coisa enquanto usuário autenticados inativos não.
Não se esqueça de testar o atributo is_active
do usuário nos métodos de permissão do seu próprio backend.
Em versões antigas, o ModelBackend
permite que usuários inativos se autentique.
Manipulação de permissões de objeto¶
O framework de permissões do Django tem uma “foundation” para objetos de permissões, embora não haja uma implementação para isso no core. Isso significa que a verificação para permissões de objetos sempre retorna False
ou uma lista vazia (dependendo da verificação realizada). Um “backend” de autenticação receberá os parâmetros nomeados obj
e user_obj
para cada método de autorização relacionado com o objeto e pode retornar o nível de permissão do objeto como for apropriado.
Permissões personalizadas¶
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
existente¶
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)
Os modelos “profile” não são especiais de maneira alguma - eles são apenas modelos Django que possuem uma relação um-para-um com o modelo “user”. Assim sendo, eles não são criados automaticamente quando um usuário é criado, más um django.db.models.signals.post_save
pode ser usado para criar ou atualizar um modelo relacionado se for apropriado.
Usar modelos relacionados resultam em “queries” adicionais ou “joins” para retornar os dados relacionados. Dependendo de suas necessidades, talvez seja uma melhor opção um modelo “user” customizado que inclua os campos relacionados, porém, relações com o modelo “user” já existente dentro das apps do seu projeto talvez justifiquem a carga extra do banco de dados.
Substituindo um modelo de Usuário
personalizado¶
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, fornecendo um valor para o AUTH_USER_MODEL
definindo a referência para um modelo personalizado:
AUTH_USER_MODEL = 'myapp.MyUser'
Este par com ponto no meio descreve o nome da app Django (o qual deve estar no seu INSTALLED_APPS
), e o nome do modelo Django que você deseja utilizar como seu modelo “user”.
Usando um modelo de usuário personalizado quando iniciando um projeto¶
Se você estiver iniciando um novo projeto, é altamente recomendado que você defina um modelo de “user” personalizado, mesmo que o modelo padrão User
seja suficiente pra você. Este modelo se comportará de maneira idêntica ao modelo “user” padrão, mas você será capaz de personalizá-lo no futuro caso a necessidade apareça.
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
pass
Não se esqueça de indicá-lo no AUTH_USER_MODEL
. Faça isso antes de criar qualquer migração ou antes de rodar um manage.py migrate
pela primeira vez.
Mudando para um modelo “user” personalizado no meio do projeto¶
Alterar o AUTH_USER_MODEL
depois que tenha criado as tabelas no banco de dados é significantemente mais difícil já que isso afeta chaves estrangeiras e relacionamentos muitos-para-muitos, por exemplo.
Está modificação não pode ser feita automaticamente e requer um conserto manual do esquema, movendo os dados da antiga tabela de usuários e, possivelmente reaplicando manualmente algumas migrações. Veja #25313 para um esboço das etapas.
Devido às limitações do recurso de dependência dinâmica do Django para modelos intercambiáveis, o modelo referenciado por AUTH_USER_MODEL
deve ser criado na primeira migração do seu aplicativo (usualmente chamada de 0001_initial
); caso contrário, você terá problemas de dependência.
Além disso, você pode ter um `` CircularDependencyError`` ao executar suas migrações, pois o Django não será capaz de quebrar automaticamente o loop de dependência devido à dependência dinâmica. Se você tiver este erro, você deverá quebrar o loop movendo os modelos dependentes, do seu modelo de usuário, para uma segunda migração. (Você pode tentar criando dois modelos normais, onde cada um possui uma ForeignKey
para o outro e ver como o makemigrations
resolve essa dependência circular.)
Apps reusáveis e AUTH_USER_MODEL
¶
Aplicações reutilizáveis não devem implmentar um modelo de usuário personalizado. Um projeto pode usar muitas aplicações, e duas aplicações reutilizáveis que implementam um modelo de usuário personalizado não poderiam ser usadas juntas. Se você precisa armazenar informação por usuário na sua aplicação, use um ForeignKey
ou OneToOneField
para o settings.AUTH_USER_MODEL
como descrito abaixo.
Referenciando o modelo Usuário
¶
Se você referênciar diretamente User
(por exemplo, referenciando ele em uma chave estrangeira), seu código não ira funcionar em projetos onde a configuração AUTH_USER_MODEL
tenha sido modificada para um modelo de usuário diferente.
-
get_user_model
()[código fonte]¶ Ao invés de fazer uma referencia direta ao
User
, você deve referenciar o modelo do usuário usando odjango.contrib.auth.get_user_model()
. Este método irá retornar o modelo de usuário ativo no momento – o modelo de usuário personalizado se este estiver especificado, ou se não, oUser
.Quando se define uma chave estrangeira ou relacionamentos muitos-para-muitos com o modelo de usuário, você deve especificar o modelo personalizado 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 a sinais enviados pelo modelo de usuário, você deve especificar o modelo personalizado definindo o
AUTH_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)
Em geral, você deve referenciar o modelo de usuário com a definição do
AUTH_USER_MODEL
em partes do códigos executadas durante o tempo de importação. Oget_user_model()
funciona somente depois que o Django já importou todos os modelos.
Definindo um modelo de usuário personalizado.¶
Considerações do design de modelo
Pense bem antes de lidar com dados no seu modelo de usuário personalizado e que não estejam diretamente relacionados com a autenticação.
Talvez seja melhor armazenar informações de usuário que são específicas daquela aplicação em um modelo que tenha um relacionamento com o modelo do usuário. Isso permite cada aplicação ter seus próprios requerimentos de dados de usuário sem risco de conflitos com outras aplicações. Por outro lado, pesquisas no banco que retornem a informação relacionada irá requerer um “join”, o que pode ter um efeito sobre a performance.
O Django espera que seu modelo de usuário personalisado siga alguns preceitos básicos.
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 personalizado compatível é herdar de AbstractBaseUser
. A AbstractBaseUser
fornece o mínimo necessário para implementar um modelo de usuário, incluindo senhas criptografadas e “resets” de senha. Você deve então fornecer alguns detalhes chaves da implementação:
-
class
models.
CustomUser
¶ -
USERNAME_FIELD
¶ Uma “string” descrevendo o nome do campo do modelo do usuário que é usado como identificador único. Geralmente será um nome de usuário de algum tipo, mas pode ser também o endereço de email, ou qualquer outro identificador único. O campo tem que ser “unique” (isto é, ter um
unique=True
na sua definição), a menos que seja utilizado um mecanismo de autenticação personalizado que permita nomes de usuários que não sejam únicos.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_FIELD
agora suportaForeignKey
s. 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_key
por padrão) de uma instância existente.
-
REQUIRED_FIELDS
¶ 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
éFalse
ou indefinido e pode incluir campos adicionais que você queira demandar quando o usuário for criado interativamente. OREQUIRED_FIELDS
não tem efeito em outras partes do Django, como criar um usuario no admin.Por exemplo, aqui é a definição parcial para um modelo de usuário que define dois campos obrigatórios - data de nascimento e peso:
class MyUser(AbstractBaseUser): ... date_of_birth = models.DateField() height = models.FloatField() ... REQUIRED_FIELDS = ['date_of_birth', 'height']
Nota
O
REQUIRED_FIELDS
deve conter todos os campos obrigatórios do seu modelo de usuário, mas não deve conter oUSERNAME_FIELD
oupassword
já que estes campos serão sempre requeridos.USERNAME_FIELD
agora suportaForeignKey
s. 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_key
por padrão) de uma instância existente.
-
is_active
¶ Um atributo booleano que indica se o usuário é considerado “active”. Este atributo é fornecido como um atributo na
AbstractBaseUser
padronizado 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 embutido
para detalhes.
-
get_full_name
()¶ 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
()¶ 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()
.
Importando “AbstractBaseUser”
New in Django 1.9.O
AbstractBaseUser
e oBaseUserManager
são importados dedjango.contrib.auth.base_user
tal que podem ser importados sem incluir odjango.contrib.auth
noINSTALLED_APPS
(isso levanta um alerta obsoleto em versões antigas e não é mais suportado no Django 1.9).-
Os atributos e métodos a seguir estão disponíveis em qualquer subclasse de AbstractBaseUser
:
-
class
models.
AbstractBaseUser
¶ -
get_username
()¶ Retorna o valor do campo denominado no
USERNAME_FIELD
.
-
clean
()¶ - New in Django 1.10.
Normaliza o nome de usuário chamando
normalize_username()
. Se sobreescrever este método, lembre-se de chamar osuper()
para manter a normlização.
-
classmethod
normalize_username
(username)¶ - New in Django 1.10.
Aplica normalização NFKC de UNICODE para nomes de usuários de modo que caracteres visualmente idênticos com pontos diferentes são considerados idênticos.
-
is_authenticated
¶ Atributo somente de leitura que está sempre definido como
True``(oposto ao `AnonymousUser.is_authenticated
que é sempreFalse
). Esta á a maneira de dizer se o usuário foi atenticado. Isso não implica em verificação de nenhuma permissão e não verifica se o usuário é ativo ou tem uma sessão válida. Mesmo que normalmente você irá verificar este atributo norequest.user
para descobrir se foi populado peloAuthenticationMiddleware
(representando o usuário logado atualmente), você deve saber se este atributo éTrue
para qualquer instância deUser
.Changed in Django 1.10:Em versões anteriores, isso era um método. O suporte a compatibilidade de versões anteriores para usar isso como um método será removido no Django 2.0.
-
is_anonymous
¶ Atributo somente de leitura o qual é sempre definido como
False
. Esta é a maneira de diferenciar objetos do tipoUser
eAnonymousUser
. Geralmente, você deve preferir usar ois_authenticated
a este atributo.Changed in Django 1.10:Em versões anteriores, isso era um método. O suporte a compatibilidade de versões anteriores para usar isso como um método será removido no Django 2.0.
-
set_password
(raw_password)¶ 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)¶ 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
()¶ 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
()¶ Retorna
False
seset_unusable_password()
foi chamado para este usuário.
-
get_session_auth_hash
()¶ Retorna um HMAC do campo senha. Usado para “Invalidação de Sessão após a Troca de Senha.” isto é, invalidar sessão no caso de alteração de password.
-
É necessário definir um “manager” personalizado para seu modelo de usuário. Se o seu modelo de usuário possui os campos username
, email
, is_staff
, is_active
, is_superuser
, last_login
, e date_joined
como o modelo “User” padrão do Django’s, você pode simplesmente usar o UserManager
do Django; porém, se o seu modelo de usuário define campos diferentes, você precisa definir um “manager” personzalido que herde de BaseUserManager
fornecendo dois métodos adicionais:
-
class
models.
CustomUserManager
¶ -
create_user
(*username_field*, password=None, **other_fields)¶ 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 ``email
como o campo username, e temdate_of_birth
como campo requerido, entãocreate_user
deve ser definido como:def create_user(self, email, date_of_birth, password=None): # create user here ...
-
create_superuser
(*username_field*, password, **other_fields)¶ 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 ``email
como o campo “username”, e temdate_of_birth
como campo requerido, entãocreate_user
deve 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.
BaseUserManager
¶ -
classmethod
normalize_email
(email)¶ Normaliza o endereço de email colocando em minúsculas a porção do domínio do endereço de email.
-
get_by_natural_key
(username)¶ 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')¶ Retorna uma senha randômica com o tamanho dado e a dada string de caracteres permitidos. Note que o calor padrão de
allowed_chars
nã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)
-
classmethod
Estendendo o Usuário
padrão do Django¶
Se você está inteiramente feliz com o modelo User
do Django e você só quer adicionar algumas informaçõ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 Definindo um modelo de usuário 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.¶
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
.SetPasswordForm
PasswordChangeForm
AdminPasswordChangeForm
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 chamadoemail
que pode ser usado para identificar o usuário e um campo booleano chamadois_active
para 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.admin
¶
Se você quer que seu modelo de usuário personalizado também funcione com o “admin”, seu modelo de usuário deve definir alguns atributos e métodos adicionais. Estes métodos permitem que o “admin” controle o acesso do usuário ao conteúdo do “admin”.
-
class
models.
CustomUser
-
is_active
¶ Retorna
True
se 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ê também irá precisar registrar seu modelo de usuário personalizado com o “admin”. Se seu modelo ersonalizado herda de django.contrib.auth.models.AbstractUser
, você pode usar a classe já existente django.contrib.auth.admin.UserAdmin
. Porém, se seu modelo de usuário herda de AbstractBaseUser
, você precisa definir uma classe personalizada de ModelAdmin
. Pode ser que seja possível herdar da django.contrib.auth.admin.UserAdmin
padrão; porém, será necessário sobrescrever qualquer das definições que se referem a campos do ``django.contrib.auth.models.AbstractUser``e que não estejam no sua classe de usuário personalizado.
Usuários personalizados e permissões¶
Para tornar fácil a inclusão do mecanismo de permissão do Django na sua classe de usuário, o Django fornece a PermissionsMixin
. Ela é uma classe de modelo abstrato que você pode incluir na hierarquia de classes do seu modelo, lhe dando todos os métodos e campos do banco de dados necessários de modo a funcionar como modelo de permissão do Django.
PermissionsMixin
fornece os seguintes métodos e atributos:
-
class
models.
PermissionsMixin
¶ -
is_superuser
¶ Booleano. Designa que este user tem todas as permissões sem assinalá-las explicitamente.
-
get_group_permissions
(obj=None)¶ 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)¶ 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)¶ Retorna
True
se o usuário tem a permissão especificada, ondeperm
está 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)¶ Retorna
True
se 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)¶ Retorna
True
se 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
.
-
Usuários personalizados e modelos de proxy¶
Uma das limitações de modelos de usuário personalizados é que ao instalar uma classe de modelo de usuário personalizado qualquer modelo “proxy” que estenda a User
irá quebrar. Modelos do tipo “proxy” devem ser baseados em uma classe base concreta; ao definir um modelo de usuário personalizado, você está removendo a habilidade do Django de identificar a classe base de maneira confiável.
Se seu projeto usa modelos “proxy”, você deve modificar o “proxy” para herdar do modelo de usuário em uso no seu projeto, ou juntar o comportamento do seu “proxy” dentro da sua subclasse de User
.
Um exemplo completo¶
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.
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
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)
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'