Questo tutorial fornirà un'introduzione ai JSON Web Tokens (JWT) e su come implementare l'autenticazione JWT in Django.
JWT è una stringa JSON codificata che viene passata nelle intestazioni per autenticare le richieste. Di solito è ottenuto da hash dati JSON con una chiave segreta. Ciò significa che il server non ha bisogno di interrogare il database ogni volta per recuperare l'utente associato a un determinato token.
Quando un utente accede correttamente utilizzando le proprie credenziali, un token Web JSON viene ottenuto e salvato nella memoria locale. Ogni volta che l'utente desidera accedere a un URL protetto, il token viene inviato nell'intestazione della richiesta. Il server verifica quindi un JWT valido nell'intestazione Autorizzazione e, se trovato, l'utente può accedere.
Un'intestazione di contenuto tipica sarà simile a questa:
Autorizzazione: Bearer eyJhbGciOiJIUzI1NiIsI
Di seguito è riportato un diagramma che mostra questo processo:
L'autenticazione è il processo di identificazione di un utente che ha effettuato l'accesso, mentre l'autorizzazione è il processo per identificare se un determinato utente ha il diritto di accedere a una risorsa Web.
In questo tutorial, stiamo costruendo un semplice sistema di autenticazione utente in Django usando JWT come meccanismo di autenticazione.
Iniziamo.
Crea una directory in cui manterrai il tuo progetto e anche un ambiente virtuale per installare le dipendenze del progetto.
mkdir myprojects cd myprojects virtual venv
Attiva l'ambiente virtuale:
fonte venv / bin / activate
Crea un progetto Django.
django-admin startproject django_auth
Installa DRF e django-rest-framework-jwt usando pip.
pip installa djangorestframework pip installa djangorestframework-jwt pip installa django
Andiamo avanti e aggiungere DRF all'elenco delle app installate in settings.py
file.
Per utilizzare JWT, è necessario configurare le autorizzazioni di django-rest-framework per accettare i token Web JSON.
Nel settings.py
file, aggiungere le seguenti configurazioni:
REST_FRAMEWORK = 'DEFAULT_AUTHENTICATION_CLASSES': ('rest_framework_jwt.authentication.JSONWebTokenAuthentication',),
Crea una nuova app chiamata utenti che gestirà l'autenticazione e la gestione degli utenti.
cd django-auth django-admin.py utenti startapp
Aggiungi l'applicazione utente all'elenco delle app installate in settings.py
file.
Useremo il database PostgreSQL perché è più stabile e robusto.
Crea il auth
database e assegnare un utente.
Passa all'account Postgres sul tuo computer digitando:
sudo su postgres
Accedere al prompt di Postgres e creare il database:
psql postgres = # CREATE DATABASE auth;
Crea un ruolo:
postgres = # CREATE ROLE django_auth WITH LOGIN PASSWORD 'asdfgh';
Concedere l'accesso al database all'utente:
postgres = # CONCEDERE TUTTI I PRIVILEGI SU DATABASE auth TO django_auth;
Installa il pacchetto psycopg2, che ci permetterà di utilizzare il database che abbiamo configurato:
pip installa psycopg2
Modifica il database SQLite attualmente configurato e utilizza il database Postgres.
DATABASE = 'default': 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': 'auth', 'USER': 'django_auth', 'PASSWORD': 'asdfgh', 'HOST': "localhost", "PORT": ",
Django è dotato di un sistema di autenticazione incorporato che è molto elaborato, ma a volte è necessario apportare delle modifiche e quindi è necessario creare un sistema di autenticazione utente personalizzato. Il nostro modello utente erediterà dal AbstractBaseUser
classe fornita da django.contrib.auth.models
.
In users / models.py, iniziamo creando il modello User per memorizzare i dettagli dell'utente.
# users / models.py da __future__ import unicode_literals dai modelli di importazione django.db dal fuso orario di importazione di django.utils da django.contrib.auth.models import (AbstractBaseUser, PermissionsMixin) classe User (AbstractBaseUser, PermissionsMixin): "" "Una base astratta classe che implementa un modello utente con funzionalità complete con autorizzazioni conformi all'amministratore. "" "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 = ['first_name', 'last_name'] def save (self, * args, ** kwargs): super (Utente, self) .save (* args, ** kwargs) return self
CAMPI RICHIESTI
contiene tutti i campi obbligatori sul modello dell'utente, ad eccezione del campo del nome utente e della password, poiché questi campi verranno sempre richiesti.
UserManager
è la classe che definisce il creare un utente
e createsuperuser
metodi. Questa classe dovrebbe venire prima del AbstractBaseUser
classe che abbiamo definito sopra. Andiamo avanti e definiamolo.
da django.contrib.auth.models import (AbstractBaseUser, PermissionsMixin, BaseUserManager) class UserManager (BaseUserManager): def _create_user (self, email, password, ** extra_fields): "" "Crea e salva un utente con l'e-mail specificata, e password. "" "se non e-mail: genera ValueError ('L'e-mail fornita deve essere impostata') prova: con transaction.atomic (): user = self.model (email = email, ** extra_fields) user.set_password (password) user.save (using = self._db) return user tranne: raise def create_user (self, email, password = None, ** extra_fields): extra_fields.setdefault ('is_staff', False) extra_fields.setdefault ('is_superuser', False ) return self._create_user (email, password, ** extra_fields) def create_superuser (self, email, password, ** extra_fields): extra_fields.setdefault ('is_staff', True) extra_fields.setdefault ('is_superuser', True) return self ._create_user (email, password = password, ** extra_fields)
Le migrazioni forniscono un modo per aggiornare lo schema del database ogni volta che i modelli cambiano, senza perdere i dati.
Crea una migrazione iniziale per il modello degli utenti e sincronizza il database per la prima volta.
python manage.py effettua la migrazione degli utenti python manage.py migrare
Creare un superutente eseguendo il seguente comando:
python manage.py createsuperuser
Creiamo un endpoint per abilitare la registrazione di nuovi utenti. Inizieremo serializzando i campi del modello Utente. I serializzatori forniscono un modo per modificare i dati in un modulo che è più facile da capire, come JSON o XML. La deserializzazione fa il contrario, ovvero la conversione di dati in un modulo che può essere salvato nel database.
Crea utenti / serializers.py e aggiungi il seguente codice.
# users / serializers.py from rest_framework import serializers from.models import User class UserSerializer (serializers.ModelSerializer): date_joined = serializers.ReadOnlyField () classe Meta (oggetto): model = Campi utente = ('id', 'email', 'first_name', 'last_name', 'date_joined', 'password') extra_kwargs = 'password': 'write_only': True
Successivamente, vogliamo creare una vista in modo che il client abbia un URL per la creazione di nuovi utenti.
In users.views.py, aggiungi quanto segue:
# users / views.py class CreateUserAPIView (APIView): # Consenti a qualsiasi utente (autenticato o meno) di accedere a questo URL permission_classes = (AllowAny,) def post (self, request): user = request.data serializer = UserSerializer (data = utente) serializer.is_valid (raise_exception = True) serializer.save () return Response (serializer.data, status = status.HTTP_201_CREATED)
Prepariamo permission_classes
a (AllowAny,)
per consentire a qualsiasi utente (autenticato o meno) di accedere a questo URL.
Crea un file utenti / urls.py
e aggiungi l'URL per abbinare la vista che abbiamo creato. Aggiungi anche il seguente codice.
# users / urls.py dall'URL di importazione django.conf.urls, modelli da .views import CreateUserAPIView urlpatterns = [url (r '^ create / $', CreateUserAPIView.as_view ()),]
Dobbiamo inoltre importare gli URL dall'applicazione utente al principale django_auth / urls.py
file. Quindi vai avanti e fallo. Stiamo usando il includere
funzione qui, quindi non dimenticare di importarlo.
# django_auth / urls.py dall'URL di importazione django.conf.urls, includi da django.contrib import admin admin urlpatterns = [url (r '^ admin /', admin.site.urls), url (r '^ user /', include ('users.urls', namespace = "users")),]
Ora che abbiamo finito di creare l'endpoint, facciamo un test e vediamo se siamo sulla buona strada. Useremo Postman per fare i test. Se non hai familiarità con Postman, è uno strumento che presenta una GUI amichevole per la costruzione di richieste e la lettura di risposte.
Come puoi vedere sopra, l'endpoint funziona come previsto.
Faremo uso del modulo Python JWT di Django-REST Framework che abbiamo installato all'inizio di questo tutorial. Aggiunge il supporto dell'autenticazione JWT per le app Django Rest Framework.
Ma prima, definiamo alcuni parametri di configurazione per i nostri token e come sono generati nel file settings.py.
# settings.py import datetime JWT_AUTH = 'JWT_VERIFY': True, 'JWT_VERIFY_EXPIRATION': True, 'JWT_EXPIRATION_DELTA': datetime.timedelta (seconds = 3000), 'JWT_AUTH_HEADER_PREFIX': 'Bearer',
JWT_VERIFY
: Solleverà un jwt.DecodeError se il segreto è sbagliato.JWT_VERIFY_EXPIRATION
: Imposta la scadenza su True, il che significa che i token scadranno dopo un certo periodo di tempo. Il tempo predefinito è cinque minuti.JWT_AUTH_HEADER_PREFIX
: Il prefisso del valore dell'intestazione Autorizzazione richiesto per essere inviato insieme al token. Lo abbiamo impostato come Portatore
, e il valore predefinito è JWT
.Nel utenti / views.py
, aggiungi il seguente codice.
@api_view (['POST']) @permission_classes ([AllowAny,]) def authenticate_user (request): try: email = request.data ['email'] password = request.data ['password'] utente = User.objects .get (email = email, password = password) se utente: try: payload = jwt_payload_handler (utente) token = jwt.encode (payload, settings.SECRET_KEY) user_details = user_details ['name'] = "% s% s "% (user.first_name, user.last_name) user_details ['token'] = token user_logged_in.send (mittente = utente .__ class__, request = richiesta, utente = utente) return Response (user_details, status = status.HTTP_200_OK) tranne Exception come e: raise e else: res = 'error': 'non può autenticare con le credenziali fornite o l'account è stato disattivato' return Response (res, status = status.HTTP_403_FORBIDDEN) tranne KeyError: res = 'error' : "fornire una e-mail e una password" return Response (res)
Nel codice sopra, la vista di login accetta nome utente e password come input, quindi crea un token con le informazioni dell'utente corrispondenti alle credenziali passate come payload e le restituisce al browser. Altri dettagli utente come il nome vengono anche restituiti al browser insieme al token. Questo token verrà utilizzato per l'autenticazione nelle richieste future.
Le classi di autorizzazione sono impostate su allowAny
dal momento che chiunque può accedere a questo endpoint.
Inoltre memorizziamo l'ultimo tempo di accesso dell'utente con questo codice.
user_logged_in.send (sender = utente .__ class__, request = request, user = user)
Ogni volta che l'utente vuole fare una richiesta API, deve inviare il token in Authers Headers per autenticare la richiesta.
Proviamo questo endpoint con Postman. Apri Postman e utilizza la richiesta per l'autenticazione con uno degli utenti creati in precedenza. Se il tentativo di accesso ha esito positivo, la risposta sarà simile a questa:
Finora, gli utenti possono registrarsi e autenticarsi. Tuttavia, hanno anche bisogno di un modo per recuperare e aggiornare le loro informazioni. Implementiamo questo.
Nel users.views.py
, aggiungi il seguente codice.
class UserRetrieveUpdateAPIView (RetrieveUpdateAPIView): # Consenti solo agli utenti autenticati di accedere a questo url permission_classes = (IsAuthenticated,) serializer_class = UserSerializer def get (self, request, * args, ** kwargs): # serializzatore per gestire la trasformazione del nostro oggetto 'User' in qualcosa che # può essere JSONified e inviato al client. serializer = self.serializer_class (request.user) return Response (serializer.data, status = status.HTTP_200_OK) def put (self, request, * args, ** kwargs): serializer_data = request.data.get ('utente', ) serializer = UserSerializer (request.user, data = serializer_data, partial = True) serializer.is_valid (raise_exception = True) serializer.save () return Response (serializer.data, status = status.HTTP_200_OK)
Prima definiamo le classi di autorizzazione e impostiamo su IsAuthenticated
poiché questo è un URL protetto e solo gli utenti autenticati possono accedervi.
Quindi definiamo a ottenere
metodo per recuperare i dettagli dell'utente. Dopo aver recuperato i dettagli dell'utente, un utente autenticato aggiornerà i propri dettagli come desiderato.
Aggiorna i tuoi URL per definire l'endpoint come segue.
users / urls.py da .views import CreateUserAPIView, UserRetrieveUpdateAPIView urlpatterns = [url (r '^ update / $', UserRetrieveUpdateAPIView.as_view ()),]
Affinché la richiesta abbia esito positivo, le intestazioni devono contenere il token JWT come mostrato di seguito.
Se si tenta di richiedere una risorsa senza l'intestazione di autenticazione, si otterrà il seguente errore.
Se un utente rimane oltre il tempo specificato in JWT_EXPIRATION_DELTA
senza effettuare una richiesta, il token scadrà e dovranno richiedere un altro token. Questo è anche dimostrato di seguito.
Questo tutorial ha coperto ciò che è necessario per creare con successo un solido sistema di autenticazione back-end con Token Web JSON.