Destaques do Django: Modelos de usuário e autenticação (Parte 1)

Publicados: 2022-03-10
Resumo rápido ↬ Um dos principais motivos para desenvolver um site dinâmico é autenticar os usuários e restringir o conteúdo. O Django fornece um poderoso modelo de usuário pronto para uso e, neste artigo, mostraremos a melhor maneira de fornecer fluxos de autenticação de usuário seguros e intuitivos.

Existem dois tipos de sites: estáticos e dinâmicos. Django é um framework para desenvolvimento de sites dinâmicos. Enquanto um site estático é aquele que apresenta apenas informações, não há interação (além de simples solicitações de página) que é registrada em um servidor. Em um site estático, o servidor envia HTML, CSS e JavaScript para um cliente e pronto. Mais recursos exigem um site dinâmico, onde o servidor armazena informações e responde à interação do usuário além de apenas servir páginas. Uma das principais razões para desenvolver um site dinâmico é autenticar os usuários e restringir o conteúdo.

Escrever, implantar e administrar um site estático é muito mais fácil, barato e seguro do que um site dinâmico. Assim, você só deve criar um site dinâmico se os recursos adicionais do paradigma dinâmico forem necessários para o seu projeto. O Django simplifica e agiliza o processo de criação de um site dinâmico com seus componentes integrados. Como um dos principais componentes de um aplicativo web dinâmico, o objeto “conta de usuário”, como a roda, é tentador a reinventar, mas a forma padrão é apropriada para a maioria dos usos. O Django fornece um poderoso modelo de usuário pronto para uso e, neste artigo, mostraremos a melhor maneira de fornecer fluxos de autenticação de usuário seguros e intuitivos.

Outras partes da série:

  • Destaques do Django: A modelagem salva as linhas (Parte 2)
  • Destaques do Django: modelos, administração e aproveitamento do banco de dados relacional (Parte 3)
  • Destaques do Django: disputando ativos estáticos e arquivos de mídia (Parte 4)

Configurando

Se você quiser criar seu próprio aplicativo Django para experimentar os conceitos deste artigo, você pode criar um diretório (e de preferência um ambiente virtual) e então executar os seguintes comandos:

 pip install django django-admin startproject PROJECTNAME cd PROJECTNAME python manage.py startapp APPNAME python manage.py migrate python manage.py runserver

Se você está procurando um passo a passo para criar seu primeiro projeto Django, o próprio site do Django oferece um ótimo. Neste artigo, não estamos usando um projeto de exemplo, mas os conceitos discutidos serão aplicados a quase todos os aplicativos Django.

Mais depois do salto! Continue lendo abaixo ↓

Modelo de usuário padrão

Fundamentalmente, o conceito de conta de usuário existe por dois motivos: controle de acesso e estado personalizado do aplicativo. O controle de acesso é a ideia de que os recursos de um sistema estão disponíveis apenas para alguns usuários. O estado personalizado depende muito da finalidade do aplicativo, mas pode incluir configurações, dados ou quaisquer outros registros específicos de um usuário individual. O modelo de User padrão do Django fornece abordagens sensatas para ambos os casos de uso.

Inicialmente, existem dois tipos de usuários em um aplicativo Django: contas de superusuários e usuários regulares. Os superusuários têm todos os atributos e privilégios das contas normais, mas também têm acesso ao painel de administração do Django, um aplicativo poderoso que exploraremos em detalhes em um artigo futuro. Essencialmente, os superusuários podem criar, editar ou excluir quaisquer dados no aplicativo, incluindo outras contas de usuário.

Fundamentalmente, o conceito de conta de usuário existe por dois motivos: controle de acesso e estado personalizado do aplicativo.

Para criar um superusuário em seu próprio aplicativo Django, execute:

 python manage.py createsuperuser

O outro benefício de uma conta de usuário é armazenar dados personalizados no banco de dados. Por padrão, o Django requer apenas um nome de usuário e senha, mas fornece campos opcionais para os usuários inserirem seu nome, sobrenome e endereço de e-mail. Você pode ler uma referência de modelo completa no site do Django. Discutiremos a extensão desse modelo abaixo.

Segurança e confiabilidade

O Django inclui um middleware substancial de gerenciamento de senhas com o modelo de usuário. As senhas de usuário devem ter pelo menos 8 caracteres, não inteiramente números, não corresponder muito ao nome de usuário e não estar em uma lista das 20.000 senhas mais comuns. Os formulários de ações do Django validam esses requisitos. Quando uma senha é enviada ao servidor, ela é criptografada antes de ser armazenada, por padrão usando o algoritmo PBKDF2 com um hash SHA256. No geral, o sistema de senha padrão oferece segurança robusta sem nenhum esforço do desenvolvedor. A menos que você tenha conhecimentos específicos e um motivo convincente para alterar a forma como as senhas são tratadas em seu aplicativo, não modifique esse comportamento.

Um outro built-in conveniente é o requisito de que os nomes de usuário sejam exclusivos. Se você pensar bem, se houvesse dois usuários com o nome de usuário “djangofan1” e o servidor recebesse uma solicitação de login para esse nome de usuário, ele não saberia qual usuário estava tentando acessar o aplicativo. Infelizmente para eles, o segundo usuário que tentar se registrar com “djangofan1” terá que escolher um nome diferente, talvez “djangofan2”. Essa restrição de exclusividade é imposta no nível do banco de dados, mas é novamente verificada pelos formulários fornecidos pelo Django.

Por fim, uma nota sobre a exclusão de usuários. Embora a exclusão de usuários seja uma possibilidade, os aplicativos mais complexos terão vários recursos vinculados a cada conta de usuário. Se você deseja excluir efetivamente um usuário sem remover esses objetos anexados, defina o campo is_active do usuário como false. Em seguida, esses outros recursos permanecem associados à conta em vez de serem excluídos, e a conta do usuário pode ser reativada a qualquer momento por um superusuário. Observe que isso não libera o nome de usuário, mas definir a conta como inativa em conjunto com a alteração do nome de usuário para um valor aleatório e exclusivo pode obter o mesmo efeito. Por fim, se as políticas do seu site ou a lei local aplicável exigirem que as contas de usuário sejam totalmente excluíveis, a abordagem is_active não será suficiente.

A menos que você tenha conhecimentos específicos e um motivo convincente para alterar a forma como as senhas são tratadas em seu aplicativo, não modifique esse comportamento.

Uso padrão

Quando você deseja registrar uma nova conta de usuário, a visualização para isso provavelmente será semelhante à seguinte em views.py :

 from django.shortcuts import render, redirect from django.contrib.auth import authenticate, login from django.contrib.auth.forms import UserCreationForm def signup(request): if request.user.is_authenticated: return redirect('/') if request.method == 'POST': form = UserCreationForm(request.POST) if form.is_valid(): form.save() username = form.cleaned_data.get('username') password = form.cleaned_data.get('password1') user = authenticate(username=username, password=password) login(request, user) return redirect('/') else: return render(request, 'signup.html', {'form': form}) else: form = UserCreationForm() return render(request, 'signup.html', {'form': form})

Vamos separar isso:

  • Se o usuário já estiver conectado, nós o redirecionaremos para fora da página de inscrição.
  • Se o método de solicitação for POST, significa que o formulário de criação de usuário já foi preenchido e é hora de criar um usuário.
    • Primeiro, construa o objeto de formulário no back-end com os dados fornecidos pelo usuário.
    • Se o formulário for válido, crie o usuário e faça o login, depois envie-o para a página principal.
    • Caso contrário, despeje-os de volta na página de criação do usuário com informações sobre quais dados eram inválidos (por exemplo, eles solicitaram um nome de usuário já em uso).
  • Caso contrário, o usuário estará acessando a página pela primeira vez e deverá ser atendido com o formulário para criação de uma nova conta.

Agora examinando o login da conta:

 from django.shortcuts import render, redirect from django.contrib.auth import authenticate, login from django.contrib.auth.forms import AuthenticationForm def signin(request): if request.user.is_authenticated: return render(request, 'homepage.html') if request.method == 'POST': username = request.POST['username'] password = request.POST['password'] user = authenticate(request, username=username, password=password) if user is not None: login(request, user) return redirect('/') else: form = AuthenticationForm(request.POST) return render(request, 'signin.html', {'form': form}) else: form = AuthenticationForm() return render(request, 'signin.html', {'form': form})

Outra divisão:

  • Se o usuário já estiver conectado, nós o redirecionaremos para fora da página de login.
  • Se o método de solicitação for POST, isso significa que o formulário de login foi preenchido e é hora de autenticar o usuário em uma conta.
    • Primeiro, autentique o usuário com os dados fornecidos pelo usuário
    • Se o nome de usuário e a senha corresponderem a uma conta, faça o login do usuário
    • Caso contrário, traga-os de volta à página de login com as informações do formulário pré-preenchidas
  • Caso contrário, o usuário está acessando a página pela primeira vez e deve ser atendido com o formulário de login.

Por fim, seus usuários podem eventualmente querer sair. O código básico para esta solicitação é simples:

 from django.shortcuts import render, redirect from django.contrib.auth import logout def signout(request): logout(request) return redirect('/')

Uma vez que o usuário tenha feito login em sua conta e até que ele faça logout naquele dispositivo, ele estará tendo uma “sessão”. Durante esse período, as solicitações subsequentes do navegador poderão acessar as páginas somente de conta. Um usuário pode ter várias sessões ativas ao mesmo tempo. Por padrão, as sessões não expiram.

Enquanto um usuário tiver uma sessão ativa em seu dispositivo, ele se registrará como True para a verificação request.user.is_authenticated . Outra maneira de restringir páginas apenas para usuários logados é o decorador @login_required acima de uma função. Existem várias outras maneiras de alcançar o mesmo, detalhadas aqui.

Se esse nível de configuração for maior do que você deseja executar, há uma abordagem ainda mais inovadora para o gerenciamento de usuários. Essas exibições de autenticação de estoque fornecem rotas, exibições e formulários padrão para gerenciamento de usuários e podem ser modificadas atribuindo-as a URLs personalizados, passando modelos personalizados ou até mesmo subclassificando as exibições para obter mais controle.

Estendendo o modelo de usuário

Geralmente, você precisa expandir o modelo de usuário para fornecer controles de acesso mais detalhados ou armazenar mais dados de usuário por conta. Exploraremos vários casos comuns abaixo.

Eliminando campos do modelo de usuário

Ao contrário do cabeçalho desta seção, não recomendo fazer alterações diretamente no modelo de usuário ou no esquema de banco de dados associado! O modelo de usuário genérico é estabelecido em seu banco de dados por padrão durante a configuração de um novo projeto Django. Tanto está vinculado ao modelo de usuário padrão que alterá-lo pode ter efeitos inesperados em seu aplicativo (especialmente se você estiver usando bibliotecas de terceiros), portanto, adicionar ou remover campos não é recomendado e não é facilitado pela estrutura.

Por padrão, os únicos dois campos obrigatórios para um usuário são nome de usuário e senha. Se você não quiser usar nenhum dos outros campos, simplesmente ignore sua existência, pois um usuário pode ser criado sem nome, sobrenome ou endereço de e-mail. Há uma coleção de campos padrão como last_login e date_joined que também podem ser ignorados se você não os quiser. Se você tivesse uma restrição técnica real que exigisse a eliminação de campos opcionais do modelo de usuário, você já saberia sobre isso e não precisaria deste artigo.

Um motivo comum pelo qual você pode querer descartar um campo no modelo de usuário é descartar o nome de usuário em favor do e-mail como um identificador exclusivo. Nesse caso, ao criar o usuário a partir de dados de formulário ou autenticar uma solicitação, basta inserir o endereço de e-mail como nome de usuário além de seu uso no campo de e-mail. O campo de nome de usuário ainda aplicará a restrição de exclusividade quando os nomes de usuário forem formatados como endereços de e-mail. Strings são strings, elas serão tratadas da mesma forma.

Tanto está vinculado ao modelo de usuário padrão que alterá-lo pode ter efeitos inesperados em seu aplicativo, especialmente se você estiver usando bibliotecas de terceiros.

Adicionando campos com um perfil

Da mesma forma, se você quiser armazenar informações extras sobre seus usuários, não tente modificar o modelo de usuário padrão. Mesmo para um único campo, defina seu próprio objeto com um relacionamento de um para um com os usuários existentes. Esse modelo extra é frequentemente chamado de Profile . Digamos que você queira armazenar um nome do meio e uma data de nascimento (dob) para cada usuário. O Profile seria definido da seguinte forma em models.py :

 from django.db import models from django.contrib.auth.models import User class Profile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) middle_name = models.CharField(max_length=30, blank=True) dob = models.DateField(null=True, blank=True)

Controle de acesso personalizado

Seu aplicativo pode ter exigido uma distinção entre diferentes tipos de usuários para acessar informações e funções. O Django fornece um sistema para criar controle de acesso personalizado e refinado: permissões e grupos.

Permissões são objetos que determinam o acesso aos recursos. Um usuário pode ter uma ou mais permissões. Por exemplo, eles podem ter acesso de leitura a uma tabela de produtos e acesso de gravação a uma tabela de clientes. A implementação exata da permissão varia substancialmente de acordo com o aplicativo, mas a abordagem do Django torna intuitivo definir permissões para dados e atribuir essas permissões aos usuários.

Aplicativos para empresas e outras grandes organizações geralmente implementam controle de acesso baseado em função. Essencialmente, um usuário pode ter várias funções, cada uma com determinadas permissões. A ferramenta do Django para implementar este padrão é o Group. Um grupo pode ter qualquer número de permissões, que podem ser atribuídas a qualquer número de grupos. Um usuário então obtém permissões não diretamente, mas por sua participação em grupos, tornando o aplicativo mais fácil de administrar.

Visão geral: integrando um provedor de pagamento

O processo preciso de integração de um processador de pagamento varia substancialmente de acordo com o aplicativo e o provedor. No entanto, vou cobrir o processo em termos gerais.

Uma das principais vantagens da terceirização de pagamentos é que o provedor é responsável por armazenar e validar dados altamente regulamentados, como informações de cartão de crédito. O serviço então compartilha algum token de usuário exclusivo com seu aplicativo junto com dados sobre seu histórico de pagamentos. Assim como adicionar o perfil, você pode criar um modelo associado ao User principal e armazenar os dados nesse modelo. Assim como as senhas, é importante seguir a integração fornecida com o provedor para evitar o armazenamento inadequado de informações confidenciais.

Visão geral: login social

O outro campo amplo e complexo que quero abordar brevemente é o login social. Grandes plataformas como Facebook e Google, bem como sites menores como GitHub, fornecem APIs para usar seus serviços para autenticar usuários. Semelhante a um provedor de pagamento, isso cria um registro em seu banco de dados vinculando uma conta a uma conta em seu banco de dados.

Você pode incluir a autenticação social em seu site para facilitar a inscrição dos usuários sem criar um novo conjunto de credenciais de login. Se seu aplicativo visa apenas clientes que já usam um site específico que oferece uma opção de autenticação social, isso pode ajudá-lo a atrair usuários desse mercado reduzindo a barreira de entrada. Além disso, se seu aplicativo pretende acessar os dados do usuário de um serviço de terceiros, vincular as contas durante a autenticação simplifica o processo de concessão de permissões.

No entanto, existem desvantagens em usar a autenticação social. Alterações ou interrupções na API do provedor terceirizado podem interromper o tempo de atividade ou as atividades de desenvolvimento do seu aplicativo. Em geral, as dependências externas adicionam complexidade ao aplicativo. Por fim, vale a pena considerar as políticas de coleta e uso de dados de terceiros com os quais você está integrando e certificar-se de que estejam alinhadas às suas expectativas e às de seus usuários.

Se você decidir que a autenticação social é adequada para seu aplicativo, felizmente, há uma biblioteca para isso. O Python Social Auth for Django é um pacote para habilitar os recursos do ecossistema de autenticação social do Python em projetos Django.

Empacotando

Por mais universal que seja a conta de usuário, seu uso generalizado pode levar à resolução dos mesmos problemas desnecessariamente. Felizmente, este artigo mostrou a você a variedade de recursos poderosos disponíveis no Django e forneceu uma compreensão das responsabilidades básicas de um aplicativo ao criar contas de usuário.

Django Highlights é uma série que apresenta conceitos importantes de desenvolvimento web em Django. Cada artigo é escrito como um guia independente para uma faceta do desenvolvimento do Django destinada a ajudar desenvolvedores e designers de front-end a alcançar uma compreensão mais profunda da “outra metade” da base de código. Esses artigos são construídos principalmente para ajudá-lo a entender a teoria e a convenção, mas contêm alguns exemplos de código, escritos em Django 3.0. Vários conceitos que abordamos neste artigo, incluindo modelos, usuários administradores, modelos e formulários, serão explorados individualmente em detalhes em artigos futuros desta série.

Outras partes da série:

  • Destaques do Django: A modelagem salva as linhas (Parte 2)
  • Destaques do Django: modelos, administração e aproveitamento do banco de dados relacional (Parte 3)
  • Destaques do Django: disputando ativos estáticos e arquivos de mídia (Parte 4)