Deze tutorial zal een inleiding geven tot JSON Web Tokens (JWT) en hoe JWT-authenticatie in Django geïmplementeerd kan worden.
JWT is een gecodeerde JSON-reeks die wordt doorgegeven in headers om verzoeken te verifiëren. Het wordt meestal verkregen door JSON-gegevens te hashen met een geheime sleutel. Dit betekent dat de server niet telkens opnieuw naar de database hoeft te zoeken om de gebruiker op te halen die aan een bepaald token is gekoppeld.
Wanneer een gebruiker zich met succes aanmeldt met zijn inloggegevens, wordt een JSON Web Token verkregen en opgeslagen in de lokale opslag. Wanneer de gebruiker toegang wil tot een beveiligde URL, wordt het token verzonden in de kop van het verzoek. De server controleert vervolgens of er een geldige JWT in de autorisatiekop staat en als deze wordt gevonden, krijgt de gebruiker toegang.
Een typische content header ziet er als volgt uit:
Autorisatie: drager eyJhbGciOiJIUzI1NiIsI
Hieronder is een diagram van dit proces:
Verificatie is het proces van het identificeren van een ingelogde gebruiker, terwijl autorisatie het proces is om vast te stellen of een bepaalde gebruiker recht heeft op toegang tot een webresource.
In deze tutorial gaan we een eenvoudig gebruikersauthenticatiesysteem in Django bouwen met JWT als het authenticatiemechanisme.
Laten we beginnen.
Maak een map waarin u uw project kunt behouden en ook een virtuele omgeving om de projectafhankelijkheden te installeren.
mkdir myprojects cd myprojects virtual venv
Activeer de virtuele omgeving:
bron venv / bin / activeren
Maak een Django-project.
django-admin startproject django_auth
Installeer DRF en django-rest-framework-jwt met behulp van pip.
pip installeer djangorestframework pip installeer djangorestframework-jwt pip installeer django
Laten we doorgaan en DRF toevoegen aan de lijst met geïnstalleerde apps in de settings.py
het dossier.
Om JWT te kunnen gebruiken, moeten we django-rest-framework-machtigingen configureren om JSON Web Tokens te accepteren.
In de settings.py
bestand, voeg de volgende configuraties toe:
REST_FRAMEWORK = 'DEFAULT_AUTHENTICATION_CLASSES': ('rest_framework_jwt.authentication.JSONWebTokenAuthentication',),
Maak een nieuwe app met de naam gebruikers die de gebruikersauthenticatie en het beheer zal afhandelen.
cd django-auth django-admin.py startapp-gebruikers
Voeg de gebruikersapp toe aan de lijst met geïnstalleerde apps in de settings.py
het dossier.
We gaan de PostgreSQL-database gebruiken omdat deze stabieler en robuuster is.
Maak het auth
database en wijs een gebruiker toe.
Schakel over naar het Postgres-account op uw computer door te typen:
sudo su postgres
Open de Postgres-prompt en maak de database aan:
psql postgres = # CREATE DATABASE auth;
Maak een rol:
postgres = # CREATE ROLE django_auth MET AANMELDEN PASSWORD 'asdfgh';
Verleen toegang tot de database voor de gebruiker:
postgres = # TOESTAAN ALLE VOORRECHTEN OP DATABASE auth TO django_auth;
Installeer het psycopg2-pakket, waarmee we de door ons geconfigureerde database kunnen gebruiken:
pip psycopg2 installeren
Bewerk de momenteel geconfigureerde SQLite-database en gebruik de Postgres-database.
DATABASES = 'standaard': 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': 'auth', 'USER': 'django_auth', 'PASSWORD': 'asdfgh', 'HOST': 'localhost', 'PORT': ",
Django wordt geleverd met een ingebouwd authenticatiesysteem dat zeer uitgebreid is, maar soms moeten we aanpassingen maken en daarom moeten we een aangepast gebruikersauthenticatiesysteem maken. Ons gebruikersmodel zal erven van de AbstractBaseUser
klas aangeboden door django.contrib.auth.models
.
In gebruikers / models.py beginnen we met het maken van het gebruikersmodel om de gebruikersgegevens op te slaan.
# users / models.py from __future__ import unicode_literals from django.db importeer modellen uit django.utils import tijdzone van django.contrib.auth.models import (AbstractBaseUser, PermissionsMixin) class User (AbstractBaseUser, PermissionsMixin): "" "Een abstracte basis klasse die een volledig gebruikersmodel implementeert met beheerderslicenties. "" "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 (User, self) .save (* args, ** kwargs) retourneer zelf
VERPLICHTE VELDEN
bevat alle vereiste velden op uw gebruikersmodel, behalve het veld voor de gebruikersnaam en het wachtwoord, aangezien deze velden altijd worden gevraagd.
UserManager
is de klasse die de definieert create_user
en createsuperuser
methoden. Deze klasse zou vóór moeten komen AbstractBaseUser
klasse die we hierboven hebben gedefinieerd. Laten we doorgaan en het definiëren.
van django.contrib.auth.models import (AbstractBaseUser, PermissionsMixin, BaseUserManager) class UserManager (BaseUserManager): def _create_user (self, email, password, ** extra_fields): "" "Creëert en bewaart een gebruiker met de gegeven e-mail, en wachtwoord. "" "if not email: raise ValueError ('De opgegeven e-mail moet zijn ingesteld') try: with transaction.atomic (): user = self.model (email = email, ** extra_fields) user.set_password (wachtwoord) user.save (using = self._db) return user except: 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, wachtwoord, ** extra_velden) def create_superuser (zelf, email, wachtwoord, ** extra_velden): extra_fields.setdefault ('is_staff', True) extra_fields.setdefault ('is_superuser', True) retourneer zelf ._create_user (email, wachtwoord = wachtwoord, ** extra_velden)
Migraties bieden een manier om uw databaseschema bij te werken telkens wanneer uw modellen wijzigen, zonder gegevens te verliezen.
Maak een eerste migratie voor ons gebruikersmodel en synchroniseer de database voor de eerste keer.
python manage.py maak migraties gebruikers python manage.py migreren
Maak een superuser door de volgende opdracht uit te voeren:
python manage.py maaktuperuser
Laten we een eindpunt maken om registratie van nieuwe gebruikers mogelijk te maken. We beginnen met het serialiseren van de velden met gebruikersmodellen. Serializers bieden een manier om gegevens te wijzigen in een vorm die gemakkelijker te begrijpen is, zoals JSON of XML. Deserialisatie doet het tegenovergestelde, namelijk het converteren van gegevens naar een formulier dat kan worden opgeslagen in de database.
Maak gebruikers / serializers.py en voeg de volgende code toe.
# users / serializers.py van rest_framework importeren serializers from.models importeren Gebruikersklasse UserSerializer (serializers.ModelSerializer): date_joined = serializers.ReadOnlyField () class Meta (object): model = Gebruikersvelden = ('id', 'email', 'first_name', 'last_name', 'date_joined', 'password') extra_kwargs = 'password': 'write_only': True
Vervolgens willen we een weergave maken zodat de client een URL heeft voor het maken van nieuwe gebruikers.
Voeg in users.views.py het volgende toe:
# users / views.py class CreateUserAPIView (APIView): # Sta elke gebruiker toe (geverifieerd of niet) om toegang te krijgen tot deze URL permission_classes = (AllowAny,) def post (self, request): user = request.data serializer = UserSerializer (data = gebruiker) serializer.is_valid (raise_exception = True) serializer.save () return Response (serializer.data, status = status.HTTP_201_CREATED)
We gaan zitten permission_classes
naar (AllowAny,)
om elke gebruiker (geverifieerd of niet) toegang te geven tot deze URL.
Maak een bestand gebruikers / urls.py
en voeg de URL toe die overeenkomt met de weergave die we hebben gemaakt. Voeg ook de volgende code toe.
# users / urls.py van django.conf.urls importeren url, patronen van .views importeren CreateUserAPIView urlpatterns = [url (r '^ create / $', CreateUserAPIView.as_view ()),]
We moeten ook URL's van de gebruikersapp naar het hoofd importeren django_auth / urls.py
het dossier. Dus ga je gang en doe dat. We gebruiken de omvatten
functie hier, dus vergeet niet om het te importeren.
# django_auth / urls.py van django.conf.urls import url, include van django.contrib import admin urlpatterns = [url (r '^ admin /', admin.site.urls), url (r '^ user /', include ('users.urls', namespace = "users")),]
Nu we klaar zijn met het maken van het eindpunt, laten we een test doen en kijken of we op schema liggen. We zullen Postman gebruiken om de tests uit te voeren. Als u niet bekend bent met Postman, is het een hulpmiddel dat een vriendelijke GUI presenteert voor het samenstellen van verzoeken en het lezen van antwoorden.
Zoals je hierboven kunt zien werkt het eindpunt zoals verwacht.
We zullen gebruik maken van de Django-REST Framework JWT Python-module die we aan het begin van deze tutorial hebben geïnstalleerd. Het voegt JWT-authenticatie-ondersteuning toe voor Django Rest Framework-apps.
Maar laten we eerst enkele configuratieparameters definiëren voor onze tokens en hoe ze worden gegenereerd in het settings.py-bestand.
# 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
: Het zal een jwt.DecodeError ophalen als het geheim verkeerd is.JWT_VERIFY_EXPIRATION
: Stelt de vervaltijd in op True, wat betekent dat tokens na verloop van tijd vervallen. De standaardtijd is vijf minuten.JWT_AUTH_HEADER_PREFIX
: Het voorvoegsel Autorisatieheaderwaarde dat moet worden verzonden samen met het token. We hebben het zo geplaatst Toonder
, en de standaard is JWT
.In gebruikers / views.py
, voeg de volgende code toe.
@api_view (['POST']) @permission_classes ([AllowAny,]) def authenticate_user (request): try: email = request.data ['email'] wachtwoord = request.data ['wachtwoord'] user = User.objects .get (email = email, password = password) if user: try: payload = jwt_payload_handler (gebruiker) 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 (afzender = gebruiker .__ class__, request = request, user = user) return Response (user_details, status = status.HTTP_200_OK) except Exception als e: raise e else: res = 'error': 'kan niet authenticeren met de opgegeven inloggegevens of de account is gedeactiveerd' return Response (res, status = status.HTTP_403_FORBIDDEN) behalve KeyError: res = 'error' : 'Geef een e-mail en een wachtwoord op' return Response (res)
In de bovenstaande code worden in de aanmeldingsweergave gebruikersnaam en wachtwoord als invoer gebruikt en wordt vervolgens een token gemaakt met de gebruikersinformatie die overeenkomt met de doorgegeven inloggegevens als payload en wordt deze teruggestuurd naar de browser. Andere gebruikersdetails zoals de naam worden ook samen met het token teruggestuurd naar de browser. Dit token wordt gebruikt voor verificatie bij toekomstige verzoeken.
De machtigingsklassen zijn ingesteld op allowAny
aangezien iedereen toegang heeft tot dit eindpunt.
We slaan ook de laatste inlogtijd van de gebruiker op met deze code.
user_logged_in.send (afzender = gebruiker .__ class__, request = request, user = user)
Telkens wanneer de gebruiker een API-aanvraag wil doen, moet deze het token in Auth Headers verzenden om het verzoek te verifiëren.
Laten we dit eindpunt testen met Postman. Open Postman en gebruik de aanvraag om te verifiëren met een van de gebruikers die u eerder hebt gemaakt. Als de inlogpoging succesvol is, ziet het antwoord er als volgt uit:
Tot nu toe kunnen gebruikers zichzelf registreren en verifiëren. Ze hebben echter ook een manier nodig om hun informatie op te halen en bij te werken. Laten we dit implementeren.
In users.views.py
, voeg de volgende code toe.
class UserRetrieveUpdateAPIView (RetrieveUpdateAPIView): # Laat alleen geverifieerde gebruikers toegang tot deze URL hebben permission_classes = (IsAuthenticated,) serializer_class = UserSerializer def get (self, request, * args, ** kwargs): # serializer om het 'User' object in iets dat # kan worden goedgekeurd en naar de klant wordt verzonden. serializer = self.serializer_class (request.user) return Response (serializer.data, status = status.HTTP_200_OK) def put (zelf, verzoek, * args, ** kwargs): serializer_data = request.data.get ('gebruiker', ) 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)
We definiëren eerst de toestemmingsklassen en stellen deze in op IsAuthenticated
omdat dit een beveiligde URL is en alleen geverifieerde gebruikers er toegang toe hebben.
We definiëren vervolgens een krijgen
methode om gebruikersgegevens op te halen. Nadat gebruikersgegevens zijn opgehaald, werkt een geverifieerde gebruiker hun gegevens naar wens bij.
Werk uw URL's bij om het eindpunt als volgt te definiëren.
gebruikers / urls.py van .views importeren CreateUserAPIView, UserRetrieveUpdateAPIView urlpatterns = [url (r '^ update / $', UserRetrieveUpdateAPIView.as_view ()),]
Om het verzoek succesvol te laten zijn, moeten de koppen het JWT-token bevatten, zoals hieronder wordt getoond.
Als u probeert een resource aan te vragen zonder de authenticatieheader, krijgt u de volgende foutmelding.
Als een gebruiker langer blijft dan de tijd die is opgegeven in JWT_EXPIRATION_DELTA
zonder een verzoek in te dienen, vervalt het token en moeten ze een ander token aanvragen. Dit wordt hieronder ook aangetoond.
Deze tutorial heeft betrekking op wat nodig is om met succes een solide back-end authenticatiesysteem met JSON Web Tokens te bouwen.