JWT-autentisering i Django

Denna handledning ger en introduktion till JSON Web Tokens (JWT) och hur man implementerar JWT-autentisering i Django.

Vad är JWT?

JWT är en kodad JSON-sträng som passeras i rubriker för att autentisera förfrågningar. Det erhålls vanligtvis med hashing JSON-data med en hemlig nyckel. Det betyder att servern inte behöver fråga databasen varje gång för att hämta den användare som är associerad med en given token.

Hur JSON webbtools fungerar

När en användare loggar in med hjälp av sina uppgifter, erhålls en JSON-webbtoken och sparas i lokal lagring. När användaren vill komma åt en skyddad URL skickas token i rubriken på begäran. Servern kontrollerar sedan efter en giltig JWT i auktoriseringshuvudet, och om den hittas kommer användaren att få åtkomst.

En typisk innehållsrubrik kommer att se ut så här:

Auktorisation: Bearer eyJhbGciOiJIUzI1NiIsI

Nedan visas ett diagram som visar denna process:

Begreppet autentisering och auktorisering

Autentisering är processen att identifiera en inloggad användare, medan behörighet är processen att identifiera om en viss användare har rätt att få tillgång till en webresurs.

API-exempel

I denna handledning kommer vi att bygga ett enkelt användarautentiseringssystem i Django med JWT som autentiseringsmekanism.

Krav

  • django
  • Pytonorm

Låt oss börja.

Skapa en katalog där du kommer att behålla ditt projekt och även en virtuell miljö för att installera projektberoende.

mkdir myprojects cd myprojects virtuell venv 

Aktivera den virtuella miljön:

källa venv / bin / aktivera 

Skapa ett Django-projekt.

django-admin startprojekt django_auth 

Installera DRF och django-rest-framework-jwt med pip.

pip installera djangorestframework pip installera djangorestframework-jwt pip installera django

Låt oss fortsätta och lägga till DRF i listan över installerade appar i settings.py fil.

Konfigurera JWT-inställningarna

För att kunna använda JWT måste vi konfigurera django-rest-ramtillbehör för att acceptera JSON Web Tokens.

settings.py fil, lägg till följande konfigurationer:

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

Skapa en ny app som heter användare som hanterar användarautentisering och hantering.

cd django-auth django-admin.py startapp-användare 

Lägg till användarprogrammet i listan över installerade appar i settings.py fil.

Ställa in databasen

Vi ska använda PostgreSQL-databasen eftersom den är stabilare och robustare.

Skapa auth databas och tilldela en användare.

Byt till Postgres-kontot på din maskin genom att skriva:

sudo su postgres

Öppna Postgres-prompten och skapa databasen:

psql postgres = # CREATE DATABASE auth;

Skapa en roll:

postgres = # SKAPA ROLLE django_auth MED LOGIN PASSWORD 'asdfgh'; 

Grant databasåtkomst till användaren:

postgres = # ALLA ALLA PRIVILEGER PÅ DATABASE auth TO django_auth;

Installera psycopg2-paketet, vilket gör att vi kan använda databasen som vi konfigurerat:

pip installera psycopg2

Redigera den för närvarande konfigurerade SQLite-databasen och använd Postgres-databasen.

DATABASER = 'default': 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': 'auth', 'USER': 'django_auth', 'PASSWORD': 'asdfgh', 'HOST' "localhost", "port": ",

Skapa modeller

Django levereras med ett inbyggt autentiseringssystem som är mycket detaljerat, men ibland behöver vi göra justeringar, och därmed behöver vi skapa ett anpassat användarautentiseringssystem. Vår användarmodell kommer att arva från AbstractBaseUser klass som tillhandahålls av django.contrib.auth.models.

I användare / models.py börjar vi genom att skapa användarmodellen för att lagra användarinformationen.

# users / models.py från __future__ importera unicode_literals från django.db importmodeller från django.utils importera tidszon från django.contrib.auth.models import (AbstractBaseUser, PermissionsMixin) klass Användare (AbstractBaseUser, PermissionsMixin): "" "En abstrakt bas klassen implementerar en fullt utrustad användarmodell med administratörskompatibla behörigheter. "" "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 spara (själv, * args, ** kwargs): super (Användare, själv) .save (* args, ** kwargs) returnera själv 

OBLIGATORISKA FÄLT innehåller alla obligatoriska fält på din användarmodell, förutom användarnamnet och lösenordet, eftersom dessa fält alltid kommer att bli uppmanade till.

UserManager är den klass som definierar skapa användare och createsuperuser metoder. Denna klass bör komma före AbstractBaseUser klass vi definierade ovan. Låt oss gå vidare och definiera det.

från django.contrib.auth.models importera (AbstractBaseUser, PermissionsMixin, BaseUserManager) klass UserManager (BaseUserManager): def _create_user (själv, email, lösenord, ** extra_fields): "" "Skapar och sparar en användare med det angivna e-postmeddelandet, och lösenord. "" "Om inte e-post: höja ValueError ('Den angivna e-postadressen måste ställas in') försök: med transaction.atomic (): user = self.model (email = email, ** extra_fields) user.set_password user.save (using = self._db) returnera användare utom: höja def create_user (self, email, password = Inga, ** extra_fields): extra_fields.setdefault ('is_staff', False) extra_fields.setdefault ('is_superuser', False ) returnera self._create_user (email, password, ** extra_fields) def create_superuser (själv, email, lösenord, ** extra_fields): extra_fields.setdefault ('is_staff', True) extra_fields.setdefault ('is_superuser', True) returnerar själv ._create_user (email, password = lösenord, ** extra_fields)

migreringar

Migreringar ger ett sätt att uppdatera ditt databasschema varje gång dina modeller ändras utan att förlora data.

Skapa en initial migrering för användarmodellen och synkronisera databasen för första gången.

python manage.py gör migranter användare python manage.py migrera

Skapa en superanvändare

Skapa en superanvändare genom att köra följande kommando:

python manage.py skapar uppkopplare

Skapa nya användare

Låt oss skapa en slutpunkt för att möjliggöra registrering av nya användare. Vi börjar med att serialisera användarmodellfälten. Serializers ger ett sätt att byta data till en form som är lättare att förstå, till exempel JSON eller XML. Deserialisering gör motsatsen, som omvandlar data till en blankett som kan sparas i databasen.

Skapa användare / serializers.py och lägg till följande kod.

# användare / serializers.py från rest_framework import serialiserare from.models import Användarklass UserSerializer (serializers.ModelSerializer): date_joined = serializers.ReadOnlyField () class Meta (object): model = Användarfält = ('id', 'email' 'first_name', 'last_name', 'date_joined', 'password') extra_kwargs = 'lösenord': 'write_only': True

CreateUserAPIView

Därefter vill vi skapa en vy så att klienten kommer att ha en URL för att skapa nya användare.

I users.views.py lägg till följande:

# användare / views.py klass CreateUserAPIView (APIView): # Tillåt någon användare (autentiserad eller inte) att få åtkomst till denna URL permission_classes = (AllowAny,) def post (själv, förfrågan): user = request.data serializer = UserSerializer (data = användare) serializer.is_valid (raise_exception = True) serializer.save () returnerar svar (serializer.data, status = status.HTTP_201_CREATED)

Vi sätter permission_classes till (AllowAny,) att tillåta någon användare (autentiserad eller inte) att komma åt den här webbadressen.

Konfigurera webbadresser

Skapa en fil användare / urls.py och lägg till webbadressen för att matcha den vy vi skapade. Lägg även till följande kod.

# users / urls.py från django.conf.urls import url, mönster från .views import CreateUserAPIView urlpatterns = [url (r '^ skapa / $', CreateUserAPIView.as_view ()),]

Vi måste också importera webbadresser från användarprogrammet till huvudmenyn django_auth / urls.py fil. Så fortsätt och gör det. Vi använder inkludera funktionen här, så glöm inte att importera den.

# django_auth / urls.py från django.conf.urls importadress, inkludera från django.contrib import admin urlpatterns = [url (r '^ admin /', admin.site.urls), url (r '^ user /', inkludera ("users.urls", namespace = "users")),] 

Nu när vi är klara att skapa slutpunkten, låt oss göra ett test och se om vi är på rätt spår. Vi kommer att använda Postman att göra testen. Om du inte är bekant med Postman är det ett verktyg som presenterar en användarvänlig GUI för att konstruera förfrågningar och läsresponser.

Som du kan se ovan fungerar slutpunkten som förväntat.

Godkännande av användare

Vi kommer att använda sig av Django-REST Framework JWT Python-modulen som vi installerade i början av denna handledning. Den lägger till JWT-autentiseringsstöd för Django Rest Framework-appar.

Men först, låt oss definiera några konfigurationsparametrar för våra tokens och hur de genereras i settings.py-filen.

# settings.py import datetime JWT_AUTH = 'JWT_VERIFY': True, "JWT_VERIFY_EXPIRATION": Sant, "JWT_EXPIRATION_DELTA": datetime.timedelta (sekunder = 3000), "JWT_AUTH_HEADER_PREFIX": "bärare",
  • JWT_VERIFY: Det kommer att höja en jwt.DecodeError om hemligheten är fel.
  • JWT_VERIFY_EXPIRATION: Ställer utgången till True, vilket betyder att Tokens löper ut efter en tidsperiod. Standardtiden är fem minuter.
  • JWT_AUTH_HEADER_PREFIX: Förkods prefix för behörighetsrubrik som krävs för att skickas tillsammans med token. Vi har satt det som Bärare, och standard är JWT.

I användare / views.py, lägg till följande kod.

@api_view (['POST']) @permission_classes ([AllowAny,]) def authenticate_user (request): försök: email = request.data ['email'] lösenord = request.data ['password'] user = User.objects .get (email = email, password = lösenord) om användaren: försök: payload = jwt_payload_handler (användare) token = jwt.encode (nyttolast, settings.SECRET_KEY) user_details =  user_details ['name'] = "% s% s "% (user.first_name, user.last_name) user_details ['token'] = token user_logged_in.send (avsändare = användare .__ class__, request = request, user = user) returnera svar (user_details, status = status.HTTP_200_OK) utom undantag som e: höja e else: res = 'error': 'kan inte verifiera med angivna referenser eller kontot har inaktiverats' returnera svar (res, status = status.HTTP_403_FORBIDDEN) utom KeyError: res = 'error' : "Vänligen ange ett e-postadress och ett lösenord" returnera svar (res)

I koden ovan tar inloggningsvisningen användarnamnet och lösenordet som inmatning, och det skapar sedan en token med användarinformationen som motsvarar de godkända referenserna som nyttolast och returnerar den till webbläsaren. Andra användaruppgifter som namn returneras också till webbläsaren tillsammans med token. Denna token kommer att användas för att verifiera i framtida förfrågningar.

Tillståndsklasserna är inställda på allowAny eftersom alla kan komma åt denna slutpunkt.

Vi lagrar också användarens senaste inloggningstid med den här koden.

user_logged_in.send (avsändare = användare .__ class__, request = request, user = user)

Varje gång användaren vill göra en API-begäran måste de skicka token i Auth Headers för att verifiera begäran.

Låt oss testa denna slutpunkt med Postman. Öppna Postman och använd begäran att autentisera med en av de användare du skapade tidigare. Om inloggningsförsöket har blivit framgångsrikt ser svaret ut så här:

Hämtar och uppdaterar användare

Hittills kan användarna registrera sig och autentisera sig själva. Men de behöver också ett sätt att hämta och uppdatera sin information. Låt oss genomföra detta.

I users.views.py, lägg till följande kod.

class UserRetrieveUpdateAPIView (RetrieveUpdateAPIView): # Tillåt endast autentiserade användare att komma åt den här url permission_classes = (IsAuthenticated,) serializer_class = UserSerializer def get (själv, förfrågan, * args, ** kwargs): # serializer som hanterar att vrida vårt "User" -objekt i något som # kan vara JSONified och skickas till klienten. serializer = self.serializer_class (request.user) return Response (serializer.data, status = status.HTTP_200_OK) def put (själv, förfrågan, * args, ** kwargs): serializer_data = request.data.get ("user" serializer.data, status = status.HTTP_200_OK) serializer = UserSerializer (request.user, data = serializer_data, partial = True) serializer.is_valid

Vi definierar först behörighetsklasserna och ställer in till IsAuthenticated eftersom det här är en skyddad URL och endast autentiserade användare kan komma åt det. 

Vi definierar sedan en skaffa sig metod för att hämta användaruppgifter. Efter att ha hämtat användaruppgifter uppdateras en autentiserad användare efter behov.

Uppdatera dina webbadresser för att definiera slutpunkten enligt följande.

användare / urls.py från .views importera CreateUserAPIView, UserRetrieveUpdateAPIView urlpatterns = [url (r '^ uppdatering / $', UserRetrieveUpdateAPIView.as_view ()),]

För att begäran ska bli framgångsrik bör rubrikerna innehålla JWT-token som visas nedan.

Om du försöker begära en resurs utan autentiseringsrubriken får du följande fel.

Om en användare stannar längre än den angivna tiden i JWT_EXPIRATION_DELTA utan att göra en förfrågan kommer symbolen att upphöra och de kommer att behöva begära ett annat token. Detta visas också nedan.

Slutsats

Denna handledning har täckt vad som är nödvändigt för att framgångsrikt bygga ett solidt back-end-autentiseringssystem med JSON Web Tokens.