El módulo de autenticación de Django ya viene incorcopado con el framework en si, y cuando lanzamos:
python manage.py migrate
Se migran las tablas que permiten el manejo de usuarios. Esto me resuelve gran parte del trabajo de sesiones, lo cual se agradece bastante.
Manos a la obra
Existe una clase AbstractUser, la cual podríamos heredar para generar nuestro propio usuario personalizado y agregar los campos que necesitemos. La voy a armar sin atributos, de momento, para que si en el futuro necesitamos agregar información especial al usuario, ya tengamos nuestra clase generada.
En models.py declaro el nuevo modelo User:
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
pass
Luego en settings.py le digo a Django que reconozca este modelo como su entidad User de su módulo de auth de la app api:
AUTH_USER_MODEL = 'api.User'
Armo la migración y al ejecutarla me dice:
ValueError: The field admin.LogEntry.user was declared with a lazy reference to 'api.user', but app 'api' doesn't provide model 'user'.
The field api.Vote.user was declared with a lazy reference to 'api.user', but app 'api' doesn't provide model 'user'.
Necesito declarar a Vote, el cual tiene una clave foranea de User, que se trata de mi usuario y no el del módulo de Django. El problema es que las migraciones ya corrieron anteriormente con la relación anterior, por lo cual no me las va a tomar.
Borro mi archivo de SQLite3.db y lo recreo con las migraciones, para que Django entienda las nuevas relaciones con mi usuario personalizado.
Auth Token y Auth User
Llegados a este punto, ya tengo un usuario personalizado, unido al módulo de autenticación de Django. Ahora voy a armar un endpoint de login en views.py, y lo voy a combinar con un componente de Auth Token que viene con DRF:
@api_view(['POST'])
def user_auth(request):
username = request.data.get('username')
password = request.data.get('password')
if not username or not password:
return Response({'error': 'Se debe indicar usuario y contraseña'}, status=status.HTTP_204_NO_CONTENT)
user = authenticate(request, username=username, password=password)
if user is None:
return Response({'error': 'El usuario o la contraseña son incorrectos'}, status=status.HTTP_400_BAD_REQUEST)
token, created = Token.objects.get_or_create(user=user)
return Response({'token': token.key}, status=status.HTTP_200_OK)
Luego defino la ruta en urls.py:
urlpatterns += [
path('auth', user_auth, name='api-auth')
]
A este método accedo mediante "POST /api/auth" con un JSON que contenga mi usuario y contraseña.
Pero, ¿qué hace mi vista user_auth?. Básicamente hace lo siguiente:
- Toma del request el user y pass.
- Si alguno de estos valores no existe, devuelve un error.
- Luego, con la función authenticate corre el proceso de login.
- Si el login es correcto, llama al método get_or_create del modelo Token, previamente migrado por haber importado el módulo authtoken.
- Finalmente devuelve dicho token, que nos servirá para mantener una sesión y decirle a la API quiénes somos.
Vamos a probarlo en Postman haciendo un POST a la ruta anteriormente indicada, con un JSON Body como este:
{
"username": "admin",
"password": "123"
}
Y nos devolverá lo siguiente:
Conclusiones
Quizá ahora la autenticación por Token parezca innecesaria, dado que no lo aplicamos a ningún endpoint, pero en el próximo capítulo van a ver la potencia de este simple string, y como impacta en nuestro objeto request.
¡Nos vemos en el próximo!
Top comments (0)