Authentification JWT dans Django

Ce tutoriel présentera les jetons Web JSON (JWT) et expliquera comment implémenter l'authentification JWT dans Django..

Qu'est-ce que JWT??

JWT est une chaîne JSON codée qui est passée dans les en-têtes pour authentifier les demandes. Il est généralement obtenu en hachant les données JSON avec une clé secrète. Cela signifie que le serveur n'a pas besoin d'interroger la base de données à chaque fois pour récupérer l'utilisateur associé à un jeton donné..

Comment fonctionnent les jetons Web JSON

Lorsqu'un utilisateur se connecte avec succès à l'aide de ses informations d'identification, un jeton Web JSON est obtenu et enregistré dans la mémoire de stockage locale. Chaque fois que l'utilisateur souhaite accéder à une URL protégée, le jeton est envoyé dans l'en-tête de la demande. Le serveur recherche alors un JWT valide dans l'en-tête Authorization et, s'il est trouvé, l'utilisateur sera autorisé à accéder..

Un en-tête de contenu typique ressemblera à ceci:

Autorisation: porteur eyJhbGciOiJIUzI1NiIsI

Ci-dessous un diagramme montrant ce processus:

Le concept d'authentification et d'autorisation

L'authentification est le processus permettant d'identifier un utilisateur connecté, tandis que l'autorisation consiste à déterminer si un utilisateur donné a le droit d'accéder à une ressource Web..

Exemple d'API

Dans ce tutoriel, nous allons construire un système d'authentification d'utilisateur simple dans Django en utilisant JWT comme mécanisme d'authentification..

Exigences

  • Django
  • Python

Commençons.

Créez un répertoire dans lequel vous conserverez votre projet ainsi qu'un environnement virtuel pour installer les dépendances du projet..

mkdir myprojects cd myprojects virtual venv 

Activer l'environnement virtuel:

source venv / bin / activate 

Créer un projet Django.

django-admin startproject django_auth 

Installer DRF et django-rest-framework-jwt en utilisant pip.

pip installer djangorestframework pip installer djangorestframework-jwt pip installer django

Continuons et ajoutons DRF à la liste des applications installées dans le répertoire settings.py fichier.

Configurer les paramètres JWT

Pour utiliser JWT, nous devons configurer les autorisations de django-rest-framework pour accepter les jetons Web JSON..

dans le settings.py fichier, ajoutez les configurations suivantes:

REST_FRAMEWORK = 'DEFAULT_AUTHENTICATION_CLASSES': ('rest_framework_jwt.authentication.JSONWebTokenAuthentication',),

Créer une nouvelle application appelée utilisateurs qui gérera l'authentification et la gestion des utilisateurs.

cd django-auth django-admin.py utilisateurs startapp 

Ajouter l’application utilisateurs à la liste des applications installées dans le settings.py fichier.

Configuration de la base de données

Nous allons utiliser la base de données PostgreSQL car elle est plus stable et robuste.

Créer le auth base de données et attribuer un utilisateur.

Basculez sur le compte Postgres sur votre machine en tapant:

sudo su postgres

Accédez à l'invite Postgres et créez la base de données:

psql postgres = # CREATE DATABASE auth;

Créer un rôle:

postgres = # CREATE ROLE django_auth AVEC MOT DE PASSE DE CONNEXION 'asdfgh'; 

Accorder l'accès à la base de données à l'utilisateur:

postgres = # DONNEZ TOUS LES PRIVILEGES A LA BASE DE DONNEES auth TO django_auth;

Installez le paquet psycopg2, ce qui nous permettra d’utiliser la base de données que nous avons configurée:

pip installer psycopg2

Editez la base de données SQLite actuellement configurée et utilisez la base de données Postgres.

BASES DE DONNEES = 'défaut': 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': 'auth', 'USER': 'django_auth', 'PASSWORD': 'asdfgh', 'HOST' 'localhost', 'PORT': ",

Création de modèles

Django est livré avec un système d'authentification intégré qui est très élaboré, mais nous avons parfois besoin de faire des ajustements, et donc de créer un système d'authentification d'utilisateur personnalisé. Notre modèle utilisateur héritera de la AbstractBaseUser classe fournie par django.contrib.auth.models.

Dans users / models.py, nous commençons par créer le modèle User pour stocker les détails de l'utilisateur..

# users / models.py from __future__ import unicode_literals de django.db modèles d'importation de django.utils importez le fuseau horaire de django.contrib.auth.models import (AbstractBaseUser, PermissionsMixin) class User (AbstractBaseUser, PermissionsMixin): "" Base abstraite classe implémentant un modèle utilisateur complet avec des autorisations conformes à l’administrateur. "" "email = models.EmailField (max_length = 40, unique = True) first_name = models.CharField (max_length = 30, blank = True) last_name = models.CharField ( max_length = 30, blank = True) is_active = models.BooleanField (default = True) is_staff = models.BooleanField (default = False) date_joined = models.DateTimeField (default = timezone.now) objects = UserManager () USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['prenom', 'prenom'] def save (self, * args, ** kwargs): super (utilisateur, auto) .save (* args, ** kwargs) renvoie self 

CHAMPS OBLIGATOIRES contient tous les champs obligatoires de votre modèle utilisateur, à l'exception du champ de nom d'utilisateur et du mot de passe, car ces champs seront toujours demandés.

UserManager est la classe qui définit la Créer un utilisateur et crée un utilisateur méthodes. Cette classe devrait venir avant la AbstractBaseUser classe que nous avons définie ci-dessus. Allons-y et définissons-le.

from django.contrib.auth.models import (AbstractBaseUser, PermissionsMixin, BaseUserManager), classe UserManager (BaseUserManager): def _create_user (auto, email, mot de passe, ** extra_fields): "" "Crée et enregistre un utilisateur avec le courrier électronique donné password. "" "sinon email: raise ValueError ('l'email donné doit être défini') essayez: avec transaction.atomic (): user = self.model (email = email, ** extra_fields) user.set_password (mot de passe) user.save (using = self._db) renvoie l'utilisateur sauf: raise def create_user (self, email, mot de passe = None, ** extra_fields): extra_fields.setdefault ('is_staff', False) extra_fields.setdefault ('is_superuser', False ) return self._create_user (email, mot de passe, ** extra_fields) def create_superuser (auto, email, mot de passe, ** extra_fields): extra_fields.setdefault ('is_staff', True) extra_fields.setdefault ('is_superuser', True) retourne self ._create_user (email, mot de passe = mot de passe, ** extra_fields)

Migrations

Les migrations permettent de mettre à jour le schéma de votre base de données chaque fois que vos modèles changent, sans perte de données..

Créer une migration initiale pour notre modèle d'utilisateurs et synchroniser la base de données pour la première fois.

python manage.py effectuer des migrations utilisateurs python manage.py migrer

Créer un superutilisateur

Créez un superutilisateur en lançant la commande suivante:

python manage.py crée un utilisateur supérieur

Créer de nouveaux utilisateurs

Créons un noeud final pour permettre l'enregistrement de nouveaux utilisateurs. Nous allons commencer par sérialiser les champs du modèle utilisateur. Les sérialiseurs permettent de modifier les données en un formulaire plus facile à comprendre, tel que JSON ou XML. La désérialisation fait l'inverse, c'est-à-dire convertir les données en un formulaire pouvant être enregistré dans la base de données..

Créez utilisateurs / serializers.py et ajoutez le code suivant.

# utilisateurs / serializers.py de rest_framework import sérialiseurs from.models import Classe utilisateur UserSerializer (serializers.ModelSerializer): date_joined = serializers.ReadOnlyField () classe Meta (objet): modèle = Champs utilisateur = ('id', 'email', 'first_name', 'last_name', 'date_joined', 'password') extra_kwargs = 'password': 'write_only': True

CreateUserAPIView

Ensuite, nous voulons créer une vue afin que le client ait une URL pour créer de nouveaux utilisateurs..

Dans users.views.py, ajoutez les éléments suivants:

# users / views.py, classe CreateUserAPIView (APIView): # Autorise tout utilisateur (authentifié ou non) à accéder à cette url permission_classes = (AllowAny,) def post (auto, requête): user = request.data serializer = UserSerializer (data = serializer.is_valid (raise_exception = True) serializer.save () return Response (serializer.data, status = status.HTTP_201_CREATED)

Nous fixons classes_autorisations à (AllowAny,) pour permettre à n'importe quel utilisateur (authentifié ou non) d'accéder à cette URL.

Configuration des URL

Créer un fichier utilisateurs / urls.py et ajoutez l'URL pour correspondre à la vue que nous avons créée. Ajoutez également le code suivant.

# users / urls.py de django.conf.urls import url, les modèles de .views import CreateUserAPIView urlpatterns = [url (r '^ create / $', CreateUserAPIView.as_view ()),]

Nous devons également importer les URL de l’application des utilisateurs vers le répertoire principal. django_auth / urls.py fichier. Alors allez-y et faites cela. Nous utilisons le comprendre fonctionne ici, alors n'oubliez pas de l'importer.

# django_auth / urls.py de l'URL d'importation django.conf.urls, inclure de l'URL django.contrib import admin urlpatterns = [url (r '^ admin /', admin.site.urls), url (r '^ user /', include ('users.urls', namespace = "users")),] 

Maintenant que nous avons fini de créer le noeud final, faisons un test et voyons si nous sommes sur la bonne voie. Nous allons utiliser Postman pour faire les tests. Si vous n'êtes pas familier avec Postman, c'est un outil qui présente une interface graphique conviviale pour la création de requêtes et la lecture de réponses..

Comme vous pouvez le voir ci-dessus, le noeud final fonctionne comme prévu..

Authentification des utilisateurs

Nous utiliserons le module Jango Python de Django-REST Framework que nous avons installé au début de ce tutoriel. Il ajoute la prise en charge de l'authentification JWT pour les applications Django Rest Framework.

Mais d’abord, définissons quelques paramètres de configuration pour nos jetons et comment ils sont générés dans le fichier settings.py.

# settings.py date et heure d'importation JWT_AUTH = 'JWT_VERIFY': True, 'JWT_VERIFY_EXPIRATION': True, 'JWT_EXPIRATION_DELTA': datetime.timedelta (secondes = 3000), 'JWT_AUTH_HEADER_PREFIX', 'Bear'
  • JWT_VERIFY: Il déclenchera un jwt.DecodeError si le secret est faux.
  • JWT_VERIFY_EXPIRATION: Définit l'expiration sur True, ce qui signifie que les jetons expireront après un certain temps. Le temps par défaut est cinq minutes.
  • JWT_AUTH_HEADER_PREFIX: Préfixe de valeur d'en-tête d'autorisation à envoyer avec le jeton. Nous l'avons défini comme Porteur, et le défaut est JWT.

Dans utilisateurs / views.py, ajouter le code suivant.

@api_view (['POST']) @permission_classes ([AllowAny,]) def authenticate_user (request): essayer: email = request.data ['email'] password = request.data ['mot de passe'] user = User.objects .get (email = email, mot de passe = mot de passe) si utilisateur: essayez: payload = jwt_payload_handler (utilisateur) token = jwt.encode (charge, paramètres.SECRET_KEY) user_details =  user_details ['name'] = "% s% s "% (user.name, user.last_name) user_details ['token'] = token user_logged_in.send (sender = user .__ class__, request = request, user = user) return Réponse (user_details, status = status.HTTP_200_OK) sauf une exception. as e: augmenter e sinon: res = 'erreur': 'ne peut pas s'authentifier avec les informations d'identification données ou le compte a été désactivé' retourner Réponse (res, status = status.HTTP_403_FORBIDDEN) sauf KeyError: res = 'error' : 'veuillez fournir un email et un mot de passe' return Response (res)

Dans le code ci-dessus, la vue de connexion utilise le nom d'utilisateur et le mot de passe en entrée, puis crée un jeton avec les informations utilisateur correspondant aux informations d'identification transmises en tant que données utiles et le renvoie au navigateur. D'autres informations sur l'utilisateur, telles que le nom, sont également renvoyées au navigateur avec le jeton. Ce jeton sera utilisé pour s'authentifier lors de futures demandes..

Les classes d'autorisation sont définies sur autoriser puisque tout le monde peut accéder à ce noeud final.

Nous enregistrons également la dernière heure de connexion de l'utilisateur avec ce code.

user_logged_in.send (sender = user .__ class__, request = request, utilisateur = utilisateur)

Chaque fois que l'utilisateur souhaite effectuer une demande d'API, il doit envoyer le jeton dans les en-têtes d'authentification afin d'authentifier la demande..

Testons ce terminal avec Postman. Ouvrez Postman et utilisez la demande pour vous authentifier auprès de l’un des utilisateurs que vous avez créé précédemment. Si la tentative de connexion réussit, la réponse ressemblera à ceci:

Récupération et mise à jour des utilisateurs

Jusqu'à présent, les utilisateurs peuvent s'inscrire et s'authentifier. Cependant, ils ont également besoin d'un moyen de récupérer et de mettre à jour leurs informations. Implémentons ceci.

Dans utilisateurs.views.py, ajouter le code suivant.

class UserRetrieveUpdateAPIView (RetrieveUpdateAPIView): # Autorise uniquement les utilisateurs authentifiés à accéder à cette URL permission_classes = (IsAuthenticated,) serializer_class = UserSerializer def get (auto, requête, * arguments, ** kwargs): # serializer pour gérer la transformation de notre objet 'User' quelque chose que # peut être JSONified et envoyé au client. serializer = self.serializer_class (request.user) return Response (serializer.data, status = status.HTTP_200_OK) def put (auto, requête, * arguments, ** kwargs): serializer_data = request.data.get ('utilisateur', ) serializer = UserSerializer (request.user, data = data_serializer, partial = True) serializer.is_valid (raise_exception = True) serializer.save () renvoie une réponse (serializer.data, status = status.HTTP_200_OK)

Nous définissons d’abord les classes d’autorisations et mettons à Est authentifié puisqu'il s'agit d'une URL protégée et que seuls les utilisateurs authentifiés peuvent y accéder. 

Nous définissons ensuite un obtenir méthode pour récupérer les détails de l'utilisateur. Après avoir récupéré les détails de l'utilisateur, un utilisateur authentifié mettra à jour ses détails à sa guise..

Mettez à jour vos URL pour définir le noeud final comme suit.

utilisateurs / urls.py depuis .views importer CreateUserAPIView, UserRetrieveUpdateAPIView urlpatterns = [url (r '^ update / $', UserRetrieveUpdateAPIView.as_view ()),]

Pour que la demande aboutisse, les en-têtes doivent contenir le jeton JWT, comme indiqué ci-dessous..

Si vous essayez de demander une ressource sans l'en-tête d'authentification, vous obtiendrez l'erreur suivante.

Si un utilisateur reste au-delà du temps spécifié dans JWT_EXPIRATION_DELTA sans faire de demande, le jeton expirera et ils devront demander un autre jeton. Ceci est également démontré ci-dessous.

Conclusion

Ce didacticiel a présenté les éléments nécessaires pour construire avec succès un système d’authentification d’arrière-plan solide avec des jetons Web JSON..