Cadastro e autenticação de usuários no Django

10/09/2017 - 6 min de leitura

DJANGO

Quando eu estava iniciando os estudos com Django, decidi que depois de fazer o tutorial Django Girls (recomendo) minha próxima aplicação teria que depender da autenticação do(a) usuário(a).

O interessante é que como eu já desenvolvia aplicações de cadastro e login em PHP no tempo, eu já estava pronto para ter que escrever tudo na mão. Mas no Django existe funções próprias que fazem o trabalho para a gente. Neste tutorial eu vou ensinar o modo que eu acho o mais fácil para a pessoa que é iniciante aprender.

Criando o formulário de cadastro

Essa parte não vou entrar em detalhes, pois acredito que se você está aprendendo django, já tem conhecimento prévio de HTML.

Digamos que a sua página de cadastro seja a primeira (index.html). Nela você deve criar um formulário contendo inputs para nome de usuário, e-mail e senha.

Após criar o formulário, você deve especificar em action o caminho para a view onde irá acontecer o cadastro.

Então digamos que você fará o cadastro em localhost:8000/cadastrar/ Tudo o que você precisa fazer é colocar /cadastrar/ no action do form.

Obs: Não esqueça do method="post".

View de cadastro

Antes de adentrar na view é importante de você tenha especificado ela em urls.py.

urlpatterns = [
    ...
    url(r'^cadastrar/$', views.cadastrar_usuario),
]

Agora podemos desenvolver a view.

Para que não tenha nenhuma falha de segurança no seu projeto, devemos exigir um requisição do tipo POST para a view ser executada. O @require_POST nos poupa o trabalho de fazer if e else.

from django.views.decorators.http import require_POST
...
@require_POST
def cadastrar_usuario(request):
    ...

Pronto. Agora temos que pegar os dados que vieram do formulário para poder cadastrar o(a) usuário(a). Pegamos esses dados com o request.POST["name-do-input"].

@require_POST
def cadastrar_usuario(request):
    nome_usuario = request.POST['campo-nome-usuario']
    email = request.POST['campo-email']
    senha = request.POST['campo-senha']

Salvando o(a) usuário(a)

Legal. Guardamos os dados dos formulário em variáveis. Mas e agora? E para pegar esses dados e salvar como um novo usuário?

Primeiro de tudo devemos importar o modelo de usuário com o comando from django.contrib.auth.models import User e depois salvar os valores no modelo de usuário.

from django.contrib.auth.models import User
from django.views.decorators.http import require_POST
...
@require_POST
def cadastrar_usuario(request):
    nome_usuario = request.POST['campo-nome-usuario']
    email = request.POST['campo-email']
    senha = request.POST['campo-senha']

    novoUsuario = User.objects.create_user(username=nome_usuario, email=email, password=senha)
    novoUsuario.save()

Obs: O Django já salva as senhas criptografadas. Mais uma camada de segurança que ele faz pra gente.

Tudo ok! Está salvando o nosso usuário. Mas se você prestar atenção, ocorre um erro se você recarregar a página ou mandar o formulário com os mesmos valores. O que será? O erro que acontece é um erro que viola a regra do campo único de username e/ou email, ou seja, não pode haver dois usuários com o mesmo username nem email. Como fugir desse erro?

Fazendo verificação para não aceitar um username ou email já cadastrados

Temos que fazer uma verificação para ver se já existe um usuário com o mesmo username ou email antes de cadastrar.

Vou mostrar um exemplo de como fazer isso:

from django.contrib.auth.models import User
from django.views.decorators.http import require_POST
...
@require_POST
def cadastrar_usuario(request):
    try:
        usuario_aux = User.objects.get(email=request.POST['campo-email'])

        if usuario_aux:
            return render(request, 'caminho para o index', {'msg': 'Erro! Já existe um usuário com o mesmo e-mail'})

    except User.DoesNotExist:
        nome_usuario = request.POST['campo-nome-usuario']
        email = request.POST['campo-email']
        senha = request.POST['campo-senha']

        novoUsuario = User.objects.create_user(username=nome_usuario, email=email, password=senha)
        novoUsuario.save()

Existem várias maneiras de fazer essas verificações. Eu só mostrei apenas um exemplo. É importante você entender o que está acontecendo.

Primeiro eu tento procurar um usuário pelo email informado. Se existir, eu retorno para a página de formulário com uma mensagem de erro, se não existir esse usuário eu cadastro um novo. Você também pode fazer uma verificação pelo username.

Ex:

@require_POST
def cadastrar_usuario(request):
    try:
        usuario_email = User.objects.get(email=request.POST['campo-email'])
        usuario_username = User.objects.get(email=request.POST['campo-nome-usuario'])

        if usuario_email or usuario_username:
            return render(request, 'caminho para o index', {'msg': 'Erro! Já existe um usuário com o mesmo e-mail ou mesmo username'})

    except User.DoesNotExist:
        Cadastrar usuário

O exemplo acima também poderia ser com outro try dentro do except. Por exemplo:

@require_POST
def cadastrar_usuario(request):
    try:
        Consulta com username

        if usuario:
            Exibe msg de erro

    except User.DoesNotExist:
        try:
            consulta com email
            
            if usuario:
                exibe msg de erro
        except User.DoesNotExist:
            Cadastrar usuário

Fazendo login

Fazer login (autenticação) é quase a mesma coisa que cadastrar, a diferença está na parte da view, que é mais fácil, na minha opinião.

Para fazer login você precisa de um formulário com input de email e senha, ou username e senha, por exemplo. Isso tudo numa outra página, pode ser login.html.

Faça o formulário, coloque o método post, adicione no action o caminho para a url de login (localhost:8000/entrar/ ou localhost:8000/login/, você quem escolhe). Em seguida aponte uma view para essa url em urls.py.

Feito tudo isso, agora vamos criar uma view chamada entrar.

@require_POST
def entrar(request):
    usuario_aux = User.objects.get(email=request.POST['email'])
    usuario = authenticate(username=usuario_aux.username,
                           password=request.POST["senha"])
    if usuario is not None:
        login(request, usuario)
        return HttpResponseRedirect('/home/')

    return HttpResponseRedirect('/')

Vamos entender o código. A primeira linha está requerendo o método post para executar. Depois vem a declaração da função entrar. Logo após estou buscando nos usuários o user que tem o email igual ao request.POST['email'], que é o email digitado no formulário de login.

Em seguida, tem essa função authenticate() que recebe o username do usuário encontrado mais a senha que ele digitou no formulário. Essa função, como o nome já diz, faz a autenticação do usuário e guarda na variável usuario.

Você talvez deve estar se perguntando porquê não pode ser usuario_aux.password em vez de request.POST["senha"]. A resposta é simples: se for usuario_aux.password SEMPRE dará certo a autenticação, mesmo se a pessoa digitou uma senha nada a ver no formulário de login, assim o(a) usuário(a) não poderá provar que ele(a) é ele(a) mesmo.

Depois de tentar a autenticação fazemos uma verificação pra ver se usuário não é nulo. Oras, se ele não for nulo é porque deu certo a autenticação. E se deu certo, podemos fazer login com a função login(). Essa função guarda o login na sessão.

Logo após eu redireciono para a url /home/ (equivalente a localhost:8000/home/)

Importante: authenticate(), login() e HttpResponseRedirect() deverão ser importados no começo do código.

from django.http import HttpResponseRedirect
from django.contrib.auth import authenticate, login, logout
...

Obs: Se você apagar o cookies e sessions do seu navegador, o usuário estará deslogado. Mas assim é muito ruim de ser feito pelo usuário, então vou mostrar outro modo.

Fazendo logout

Fazer logout é muito muito muito muito (já disse muito?) fácil. Tudo o que precisa ser feito é ter um botão em algum lugar da sua aplicação que te mande pra uma view onde será realizado o logout. O código dessa view:

@login_required
def sair(request):
    logout(request)
    return HttpResponseRedirect('/')

@login_required é um modo de dizer para o Django que para ter acesso a view sair o usuário tem que estar logado no sistema.

Obs: Não esqueça de importar o @login_required com from django.contrib.auth.decorators import login_required

A linha logout(request) está deslogando o usuário da sessão. E depois estou mandando ele para a raiz do projeto (onde fica a página index, que é a do formulário de cadastro e/ou login). Essa função não precisa ser importada de novo, pois já importamos junto com o authenticate() e login().

Dica: Você pode melhorar ainda mais o seu código com a função is_authenticated. Ela verifica se o usuário está logado. Muito interessante para a view index, pois qual é o sentido de mostrar o formulário de login/cadastro se o usuário já está logado?

O código fica mais ou menos assim:

def index(request):
    if request.user.is_authenticated:
        return HttpResponseRedirect("/home/")
    else:
        return render(request, "caminho para index.html")

Para mais informações sobre login e autenticação :  documentação do Django.

Se você não sabe fazer upload de imagens no Django Admin esse post pode te ajudar. E não esqueça de dar uma olhada nos outros posts.

Para esse tutorial usei Django 1.11 e Python3.5

Compartilhe

Twitter