Provavelmente você já precisou criar páginas em seu site protegidas por alguma forma de autenticação.
Neste artigo vamos ver como criar uma autenticação com usuário e senha no Django utilizando class-based views.
Apesar de ver em vários lugares na internet o Django sendo utilizado com funções, pessoalmente acho que a organização utilizando classes pode nos dar um código muito mais limpo e legível, além de facilitar a modularidade do projeto.
Instalação
Para quem nunca criou uma aplicação Django, vamos cobrir alguns passos básicos aqui, então você não precisa de muito conhecimento prévio. A página oficial do Django tem um ótimo tutorial para quem está começando.
Vamos instalar o django em nosso virtualenv e criar um projeto chamado project
com um aplicativo chamado main
.
$ pip install django
$ django-admin startproject project
$ cd project
$ python manage.py startapp main
Configuração
Vamos começar adicionando o app que criamos ao settings.py
.
INSTALLED_APPS = [
...,
'main'
]
Modificar o arquivo de views para um pacote python:
- excluir o arquivo
views.py
; - criar uma pasta chamada views; e
- criar os arquivos
__init__.py
,index.py
,signup.py
,login.py
elogout.py
na pasta views como abaixo.
from django.views import View
class IndexView(View):
def get(self, request):
pass
from django.views import View
class SignupView(View):
def get(self, request):
pass
from django.views import View
class LoginView(View):
def get(self, request):
pass
from django.views import View
class LogoutView(View):
def get(self, request):
pass
Agora vamos criar um arquivo de urls para o app main:
from django.urls import path
from main.views.index import IndexView
from main.views.signup import SignupView
from main.views.login import LoginView
from main.views.logout import LogoutView
urlpatterns = [
path('', IndexView.as_view(), name='index'),
path('signup/', SignupView.as_view(), name='signup'),
path('login/', LoginView.as_view(), name='login'),
path('logout/', LogoutView.as_view(), name='logout'),
]
E importá-lo no arquivo de urls do projeto:
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('main.urls')),
]
Cadastro
Uma página de cadastro não é necessária em 100% dos projetos, mas para efeitos didáticos vamos ver neste artigo como criar uma.
Primeiro vamos criar um formulário para realizar o cadastro com campos de usuário, senha e confirmação de senha.
from django import forms
class SignupForm(forms.Form):
username = forms.CharField(label = 'Usuário')
password1 = forms.CharField(label = 'Senha', widget = forms.PasswordInput)
password2 = forms.CharField(label = 'Confirme', widget = forms.PasswordInput)
Na requisição GET da página de cadastro basta criarmos um novo formulário de signup.
from django.shortcuts import render
from django.views import View
from django.urls import reverse
from django.http import HttpResponseRedirect
from django.contrib.auth.models import User
from main.forms import SignupForm
class SignupView(View):
def get(self, request):
data = { 'form': SignupForm() }
return render(request, 'main/signup.html', data)
No template, basta utilizar a tag {{ form }}
ou então os campos do formulário.
<form method="POST" action="{% url 'signup' %}">
{% csrf_token %}
{% for field in form %}
<b>{{ field.label }}</b>: {{ field }}
<br><br>
{% endfor %}
<input type="submit" value="Cadastrar" />
</form>
O que resulta numa tela bem simples, como essa:

Na requisição POST vamos criar o formulário a partir do request
e validar os dados recebidos. Com os dados validados, podemos criar o usuário e redirecionar para a página de login.
Caso os dados não sejam válidos, renderizamos a página de cadastro novamente mas agora com uma variável de erro para dar um feedback ao usuário.
from django.shortcuts import render
from django.views import View
from django.urls import reverse
from django.http import HttpResponseRedirect
from django.contrib.auth.models import User
from main.forms import SignupForm
class SignupView(View):
def get(self, request):
data = { 'form': SignupForm() }
return render(request, 'main/signup.html', data)
def post(self, request):
form = SignupForm(data=request.POST)
if form.is_valid():
username = form.cleaned_data.get('username')
password1 = form.cleaned_data.get('password1')
password2 = form.cleaned_data.get('password2')
if username and password1 and password2 \
and password1 == password2:
user = User.objects.create_user(
username = username,
password = password1
)
if user:
return HttpResponseRedirect(reverse('login'))
data = {
'form': form,
'error': 'Usuário ou senha inválidos'
}
return render(request, 'main/signup.html', data)
E para mostrar o erro para o usuário vamos adicionar uma condição no template que verifica se existe a variável ou não.
<form method="POST" action="{% url 'signup' %}">
{% csrf_token %}
{% for field in form %}
<b>{{ field.label }}</b>: {{ field }}
<br><br>
{% endfor %}
{% if error %}
<span style="color: red;">{{ error }}</span>
<br><br>
{% endif %}
<input type="submit" value="Cadastrar" />
</form>
Nos fomulários, não podemos esquecer do seguinte:
- os atributos
method
eaction
do formulário; - a tag
{% csrf_token %}
para criar um token contra cross-site request forgery; e - um elemento do tipo
submit
.
Autenticação
Agora que já configuramos o cadastro, podemos iniciar a autenticação propriamente dita. Vamos criar outro formulário para o login com os campos de usuário e senha.
from django import forms
class SignupForm(forms.Form):
username = forms.CharField(label = 'Usuário')
password1 = forms.CharField(label = 'Senha', widget = forms.PasswordInput)
password2 = forms.CharField(label = 'Confirme', widget = forms.PasswordInput)
class LoginForm(forms.Form):
username = forms.CharField(label = 'Usuário')
password = forms.CharField(label = 'Senha', widget = forms.PasswordInput)
Com isso, estamos prontos para utilizá-lo na requisição GET do login:
from django.views import View
class LoginView(View):
def get(self, request):
data = { 'form': LoginForm() }
return render(request, 'main/login.html', data)
E no template, basta utilizar a tag {{ form }}
ou então os campos do formulário. Vamos também adicionar a condição em caso de erro como na página de cadastro.
<form method="POST" action="{% url 'login' %}">
{% csrf_token %}
{% for field in form %}
<b>{{ field.label }}</b>: {{ field }}
<br><br>
{% endfor %}
{% if error %}
<span style="color: red;">{{ error }}</span>
<br><br>
{% endif %}
<input type="submit" value="Enviar" />
</form>
O que resulta numa tela bem simples, como essa:

Para receber as informações do POST, nossa view deve receber os dados e criar um formulário vazio do tipo LoginForm
. Depois de validar com o método is_valid()
do Django, pegamos os valores de username
a password
para autenticar o usuário. Se a autenticação retornar algo válido, podemos logar o usuário no sistema.
A função
login()
atribui à variávelrequest
o usuário que foi logado, podendo ser acessado usandorequest.user
posteriormente.
from django.shortcuts import render
from django.views import View
from django.urls import reverse
from django.http import HttpResponseRedirect
from django.contrib.auth import authenticate, login
from main.forms import LoginForm
class LoginView(View):
def get(self, request):
data = { 'form': LoginForm() }
return render(request, 'main/login.html', data)
def post(self, request):
form = LoginForm(data=request.POST)
if form.is_valid():
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
if username and password \
and authenticate(username=username, password=password):
login(request, user)
return HttpResponseRedirect(reverse('index'))
data = {
'form': form,
'error': 'Usuário ou senha inválidos'
}
return render(request, 'main/login.html', data)
Na IndexView
, vamos adicionar o mixin LoginRequiredMixin
para que ela só possa ser acessada se o usuário estiver logado.
Além disso, o mixin redireciona os usuários em caso de acesso a uma página ainda não autenticado. Esse redirecionamento é feito por padrão para a url /accounts/login
.
Vamos modificar para nossa url de login adicionando a seguinte linha no settings.py.
LOGIN_URL = '/login/'
Agora basta adicionar o mixin na definição da classe.
from django.shortcuts import render
from django.views import View
from django.contrib.auth.mixins import LoginRequiredMixin
class IndexView(LoginRequiredMixin, View):
def get(self, request):
data = { 'user': request.user }
return render(request, 'main/index.html', data)
E no template, apenas mostrar o username
do usuário.
olá, {{ request.user.username }}
Finalmente, vamos definir a LogoutView
para deslogar o usuário do sistema.
from django.views import View
from django.urls import reverse
from django.http import HttpResponseRedirect
from django.contrib.auth import logout
from django.contrib.auth.mixins import LoginRequiredMixin
class LogoutView(LoginRequiredMixin, View):
def get(self, request):
logout(request)
return HttpResponseRedirect(reverse('login'))
Com isso fechamos as views básicas para qualquer sistema de autenticação no Django baseado em usuário e senha. Claro que o processo pode ser muito mais sofisticado do que mostramos aqui, mas este já é um ótimo ponto de partida para qualquer projeto.
Código
O código completo deste artigo está disponível no github
django-basic-auth (this link opens in a new window) by matheusvanzan (this link opens in a new window)
Código criado para o artigo Autenticação com class-based views no Django
Referências
- Imagem de John Salvino no Unsplash.
- Documentação e tutorial do Django.
- Artigo da Wikipédia sobre cross-site request forgery.