Autenticação JWT com DRF
De todas as features importantes que devem existir em uma aplicação, a autenticação é uma das mais importantes. É claro, estamos falando de aplicações que envolvem a utilização de usuários dentro das diversas regras de negócio que existirão na aplicação.
Existem inúmeras formas de nos autenticar com Django, uma delas é a por sessão, que por padrão já é utilizada. Entretanto, para a grande maioria dos sistemas desenvolvidos uma autenticação por sessão não seria a melhor recomendada. Para isso, temos diversas formas de nos autenticar, uma delas é por JSON Web Tokens (JWT), na qual usaremos nesse artigo.
Setup Environment
Antes de tudo, precisamos criar nosso ambiente virtual, para isso, podemos utilizar virtualenv, pipenv, poetry ou outras ferramentas. Se você ainda não tem o virtualenv instalado em sua máquina, faça a instalação usando
pip install virtualenv
criando o ambiente virtual
python3 -m venv [nome_do_seu_ambiente]
ou
virtualenv [nome_do_seu_ambiente]
Finalmente, para ativar o nosso ambiente
source [nome_do_seu_ambiente]/bin/activate
Install django
Com o nosso ambiente ativado, iremos começar a construir o nosso projeto. Necessitaremos adicionar as seguintes dependências
pip install django djangorestframework djangorestframework-simplejwt
Estarei usando as seguintes versões
Django==4.1.5
djangorestframework==3.14.0
djangorestframework-simplejwt==5.2.2
PyJWT==2.6.0
Concluindo a instalação das bibliotecas, precisaremos criar o projeto, onde teremos todas as configurações da nossa aplicação e também a nossa aplicação de autenticação.
django-admin startproject core .
e
django-admin startapp profile
Com o projeto e nosso app de autenticação criados, poderemos adicionar o rest_framework, simplejwt e o app profile dentro das configurações do nosso projeto.
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'profile',
'rest_framework_simplejwt',
]
App User
Temos dois caminhos, criar um modelo específico que determina os usuários da nossa aplicação ou usar o próprio modelo que o django nos fornece, para este último podemos importar com o seguinte caminho:
from django.contrib.auth.models import User
Sendo bem franco, para uma aplicação mínima, não vejo problema em usar a presente abordagem, entretanto, se você pensa em escalar sua aplicação, ou customizar seu usuário ao longo do tempo, será melhor fazer um override nesse User.
from django.db import models
from django.contrib.auth.models import AbstractUser #1
class Profile(AbstractUser):
class GenderChoices(models.IntegerChoices):
MAN = 1, 'Man'
WOMAN = 2, 'Woman'
full_name = models.CharField(max_length=100, blank=True)
cpf = models.CharField(max_length=11, blank=True)
gender = models.IntegerField(default=GenderChoices.MAN, choices=GenderChoices.choices)
email = models.EmailField(max_length=254, unique=True) #2
USERNAME_FIELD = 'email' # 3
REQUIRED_FIELDS = [] # 4
- O AbstractUser como o próprio nome diz é um modelo abstrato que o User padrão usa, herdando os atributos que o mesmo possui. Também podemos adicionar novos campos, como assim fazemos com o full_name, cpf, gender e email.
- Já temos esse campo email no AbstractUser, entretanto, como esse será o nosso campo para fazer login, necessitamos defini-lo como um campo único. Ou seja, não podemos ter dois emails iguais.
- USERNAME_FIELD define o campo que iremos usar para fazer o login na nossa api. Por padrão é usado o próprio username do AbstractUser, porém, a grande maioria das aplicações hoje em dia continua usando o email.
- Precisa estar junto do USERNAME_FIELD
Create migrations
Para consolidar tudo o que fizemos até agora, criaremos o arquivo de migração e criar o modelo de usuário no nosso banco de dados. Antes de fazermos isso, precisamos definir qual o nosso novo usuário .
core/settings.py
AUTH_USER_MODEL = 'profile.Profile'
profile: representa o nome do app que você criou e o modelo do seu usuário
Necessitamos fazer essa alteração porque por padrão o django marca o User como modelo correspondente ao usuário. Se investigarmos essa mesma variável no projeto do django veremos
django/conf/global_settings.py
AUTH_USER_MODEL = "auth.User"
AUTHENTICATION_BACKENDS = ["django.contrib.auth.backends.ModelBackend"]
Por isso, se você optou em fazer o override do seu usuário, não se esqueça de mudar. Com as devidas configurações feitas, podemos criar nossa migração.
python manage.py makemigrations
Se tivermos sucesso, receberemos a seguinte mensagem no terminal
Migrations for 'profile':
profile/migrations/0001_initial.py
- Create model Profile
Com o arquivo de migração criado, podemos enfim criar o nosso usuário dentro do banco de dados com o python manage.py migrate
Create user
python manage.py shell
from profile.models import Profile
profile = Profile.objects.create(email='peidrao@email.com')
profile.set_password('123')
profile.save()
Agora temos o nosso primeiro usuário e usaremos ele para fazer o login.
Configure JWT
E importante definir nas nossas configurações a forma que o django se autenticará, por padrão a autenticação e por sessão, como foi falado no inicio.
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
)
}
Para concluir, vamos adicionar a url onde existe o endpoint para autenticação.
core/urls.py
from django.contrib import admin
from django.urls import path
from rest_framework_simplejwt.views import TokenObtainPairView
urlpatterns = [
path('admin/', admin.site.urls),
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
]
Testing
curl \
-X POST \
-H "Content-Type: application/json" \
-d '{"email": "peidrao@email.com", "password": "123"}' \
http://localhost:8000/api/token/