Auch wenn Sie sich den Inhalt bisher nicht ansehen, können Sie den Inhalt dieser Zeit verstehen. Ich hoffe, Sie können bis zum Ende mit mir in Kontakt bleiben. : entspannt:
Dies ist eine Abkürzung für JSON Web Token. Es ist möglich, beliebige Informationen (Ansprüche) im Token zu speichern. Beispielsweise generiert der Server ein Token, das die Informationen "Als Administrator angemeldet" für den Client enthält. in der Lage sein. Der Client kann das Token verwenden, um zu beweisen, dass er als Administrator angemeldet ist. - [Wikipedia] (https://ja.wikipedia.org/wiki/JSON_Web_Token)
Sie können die JWT-Anmeldung einfach mithilfe der Bibliothek django-rest-framework-jwt implementieren. Es ist einfacher, auf verschiedene Arten anzupassen, wenn Sie es direkt schreiben, also schreiben Sie es direkt.
pip install Django
pip install djangorestframework
pip install markdown
pip install django-filter
django-admin startproject jwttest
cd jwttest
python manage.py runserver
Wenn Sie den Server starten und die Rakete normal sehen, ist dies in Ordnung.
Erstellen Sie eine neue App.
python manage.py startapp api
Fügen Sie es zusammen mit "rest_framework" zu "INSTALLED_APPS" hinzu.
jwttest/settings.py
INSTALLED_APPS = [
...
'rest_framework',
'api'
]
Erstellen Sie ein Benutzermodell für die Anmeldung.
jwtest/api/models.py
from django.db import models
class UserInfo(models.Model):
username = models.CharField(max_length=50, unique=True, db_index=True)
password = models.CharField(max_length=100, db_index=True)
info = models.CharField(max_length=200)
Führen Sie die DB-Migration aus.
python manage.py makemigrations
python manage.py migrate
Installieren Sie die Bibliothek für die JWT-Token-Generierung.
pip install pyjwt
Fügen Sie eine Klasse für die Anmeldung hinzu, Fügen Sie den Ordner "utls" unter dem Verzeichnis "api" hinzu und fügen Sie eine neue Datei "auth.py" hinzu.
api/utils/auth.py
import time
import jwt
from jwttest.settings import SECRET_KEY
from rest_framework.authentication import BaseAuthentication
from rest_framework import exceptions
from api.models import UserInfo
class NormalAuthentication(BaseAuthentication):
def authenticate(self, request):
username = request._request.POST.get("username")
password = request._request.POST.get("password")
user_obj = UserInfo.objects.filter(username=username).first()
if not user_obj:
raise exceptions.AuthenticationFailed('Authentifizierungsfehler')
elif user_obj.password != password:
raise exceptions.AuthenticationFailed('Ich habe kein Passwort')
token = generate_jwt(user_obj)
return (token, None)
def authenticate_header(self, request):
pass
#Generieren Sie ein Token mit der soeben installierten JWT-Bibliothek
#Der Inhalt des Tokens enthält Benutzerinformationen und Zeitüberschreitung
#Es wurde behoben, dass der Timeout-Schlüssel exp ist
#Dokument: https://pyjwt.readthedocs.io/en/latest/usage.html?highlight=exp
def generate_jwt(user):
timestamp = int(time.time()) + 60*60*24*7
return jwt.encode(
{"userid": user.pk, "username": user.username, "info": user.info, "exp": timestamp},
SECRET_KEY).decode("utf-8")
Fügen Sie auch eine Ansicht für die Anmeldung hinzu. Wenn die Anmeldung erfolgreich ist, wird JWT zurückgegeben. Fügen Sie die zuvor erstellte "NormalAuthentication" zu "authentication_classes" hinzu.
api/views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from .utils.auth import NormalAuthentication
class Login(APIView):
authentication_classes = [NormalAuthentication,]
def post(self, request, *args, **kwargs):
return Response({"token": request.user})
URL hinzufügen.
jwttest/urls.py
...
from api.views import Login
urlpatterns = [
...
path('login/', Login.as_view()),
]
Fügen Sie eine Benutzerinformation hinzu![B2DC6C55-949F-4FB9-ADCB-ED3C0F894B1E_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/9608aed2 -dfb2-7b90-bce8-5bf6bc953926.jpeg)
Starten Sie den Server und versuchen Sie, sich anzumelden. Lassen Sie uns das zurückgegebene JWT mit https: // jwt.io / analysieren. Das JWT enthält die von Ihnen angegebenen Informationen. Erstellen Sie eine Ansicht, die Sie nur sehen können, wenn Sie angemeldet sind, und verwenden Sie dieses Token, um darauf zuzugreifen. Fügen Sie zunächst die Authentifizierungsklasse für JWT zu "api / utils / auth.py" hinzu.
api/utils/auth.py
...
class JWTAuthentication(BaseAuthentication):
keyword = 'JWT'
model = None
def authenticate(self, request):
auth = get_authorization_header(request).split()
if not auth or auth[0].lower() != self.keyword.lower().encode():
return None
if len(auth) == 1:
msg = "Autorisierung deaktiviert"
raise exceptions.AuthenticationFailed(msg)
elif len(auth) > 2:
msg = "Autorisierung Kein ungültiger Speicherplatz"
raise exceptions.AuthenticationFailed(msg)
try:
jwt_token = auth[1]
jwt_info = jwt.decode(jwt_token, SECRET_KEY)
userid = jwt_info.get("userid")
try:
user = UserInfo.objects.get(pk=userid)
user.is_authenticated = True
return (user, jwt_token)
except:
msg = "Benutzer existiert nicht"
raise exceptions.AuthenticationFailed(msg)
except jwt.ExpiredSignatureError:
msg = "Zeitüberschreitung des Tokens"
raise exceptions.AuthenticationFailed(msg)
def authenticate_header(self, request):
pass
...
Es wurden Ansichten zu api / views.py
hinzugefügt, auf die ohne Anmeldung nicht zugegriffen werden kann.
api/views.py
...
from rest_framework.permissions import IsAuthenticated
...
class Something(APIView):
authentication_classes = [JWTAuthentication, ]
#Machen Sie es nur angemeldeten Benutzern zugänglich.
permission_classes = [IsAuthenticated, ]
def get(self, request, *args, **kwargs):
return Response({"data": "Es ist der Inhalt"})
...
Ich werde versuchen, darauf zuzugreifen, nachdem ich die URL hinzugefügt habe.
python:jwttest:urls.py
path('data/', Something.as_view())
Erstens Zugriff ohne Token. Es wurde zurückgegeben, dass keine Authentifizierungsdaten angegeben wurden.
Nachdem ich das Token hinzugefügt hatte, konnte ich darauf zugreifen.
Das war's, aber ich möchte eine Analyse des Login-bezogenen Quellcodes des Django REST-Frameworks hinzufügen. Bitte lesen Sie, wenn Sie interessiert sind. : entspannt:
Ich werde es basierend auf dem Code analysieren, den ich zuvor geschrieben habe. CBV (Klassenbasierte Ansichten) Wenn verwendet, wird "Versand" ausgeführt. Mit diesem als Eingang werden wir uns den Quellcode ansehen. Fügen Sie der Betrachtungsklasse, die ich zuvor geschrieben habe, "self.dispatch ()" hinzu, um es zu betrachten.
api/view.py
...
class Login(APIView):
authentication_classes = [NormalAuthentication, ]
def post(self, request, *args, **kwargs):
#Fügen Sie den Quellcode hinzu und folgen Sie ihm
#Bei Verwendung von PyCharm
#Befehl auf dem Mac+klicken
#Alt im Gewinn+Sollte ein Klick sein
self.dispatch()
return Response({"token": request.user})
...
Das Ziel ist "def dispatch (self, request, * args, ** kwargs)" in Zeile 481 von "rest_framework / views.py". Werfen wir einen Blick auf den Inhalt der Funktion "initialize_request" in Zeile 488.
rest_framework/views.py
def dispatch(self, request, *args, **kwargs):
...
#Schauen wir uns den Inhalt dieser Funktion an
request = self.initialize_request(request, *args, **kwargs)
self.request = request
Die Definition des Inhalts befindet sich in Zeile 381 von "rest_framework / views.py".
rest_framework/views.py
def initialize_request(self, request, *args, **kwargs):
"""
Returns the initial request object.
"""
parser_context = self.get_parser_context(request)
return Request(
request,
parsers=self.get_parsers(),
#Hier
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
Und wenn Sie sich den Inhalt von "self.get_authenticators ()" in Zeile 390 ansehen, Ich habe den folgenden Code, der aus "self.authentication_classes" stammt. Was ist die Authentifizierungsklasse unter Verwendung der entsprechenden CBV?
rest_framework/views.py
def get_authenticators(self):
"""
Instantiates and returns the list of authenticators that this view can use.
"""
return [auth() for auth in self.authentication_classes]
Wenn Sie der Definition von "self.authentication_classes" folgen,
Zeile 109 von rest_framework / views.py
hat die folgende Definition:
rest_framework/views.py
class APIView(View):
...
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
Daher gibt es zwei Stellen, an denen Sie direkt definieren können, welche Authentifizierungsklasse verwendet werden soll.
api/views.py
...
class Login(APIView):
#Hier
authentication_classes = [NormalAuthentication, ]
def post(self, request, *args, **kwargs):
return Response({"token": request.user})
...
REST_FRAMEWORK
in settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': ['api.utils.auth.NormalAuthentication']
}
Nachdem Sie die Beziehung zwischen CBV und der Authentifizierungsklasse verstanden haben, schauen wir uns die Funktionen der Authentifizierungsklasse an. Wir folgen auch aus "dispatch", "self.initial (request, * args, ** kwargs)" in Zeile 493 von "rest_framework / views.py".
rest_framework/views.py
def dispatch(self, request, *args, **kwargs):
...
try:
self.initial(request, *args, **kwargs)
...
Ich werde der Definition folgen. Zeile 395 von rest_framework / views.py
.
Es gibt perform_authentication
, wir werden weiter gehen.
python:rest_framework.py/views.py
...
def initial(self, request, *args, **kwargs):
...
self.perform_authentication(request)
...
Darüber hinaus ist request.user
.
rest_framework/views.py
...
def perform_authentication(self, request):
"""
Perform authentication on the incoming request.
Note that if you override this and simply 'pass', then authentication
will instead be performed lazily, the first time either
`request.user` or `request.auth` is accessed.
"""
request.user
...
Seine Definition befindet sich in Zeile 213 von "rest_framework / request.py".
rest_framework/request.py
...
@property
def user(self):
"""
Returns the user associated with the current request, as authenticated
by the authentication classes provided to the request.
"""
if not hasattr(self, '_user'):
with wrap_attributeerrors():
self._authenticate()
return self._user
...
Werfen wir einen Blick auf die Definition von "self._authenticate ()". Zeile 366 von rest_framework / request.py
.
Der Inhalt besteht darin, die Klasse aus der Liste der CBV-Authentifizierungsklassen zu extrahieren und die Methode "authentifizieren" dieser Klasse auszuführen.
Das Ergebnis der Ausführung ist ein "Tupel" mit zwei Elementen, das erste der Tupel ist "self.user" und das zweite ist "self.auth".
rest_framework/request.py
def _authenticate(self):
"""
Attempt to authenticate the request using each authentication instance
in turn.
"""
for authenticator in self.authenticators:
try:
user_auth_tuple = authenticator.authenticate(self)
except exceptions.APIException:
self._not_authenticated()
raise
if user_auth_tuple is not None:
self._authenticator = authenticator
self.user, self.auth = user_auth_tuple
return
self._not_authenticated()
Schauen wir uns vor diesem Hintergrund die zuvor definierte Authentifizierungsklasse für JWT an.
api/utils/auth.py
class JWTAuthentication(BaseAuthentication):
keyword = 'JWT'
model = None
def authenticate(self, request):
auth = get_authorization_header(request).split()
if not auth or auth[0].lower() != self.keyword.lower().encode():
return None
if len(auth) == 1:
msg = "Autorisierung deaktiviert"
raise exceptions.AuthenticationFailed(msg)
elif len(auth) > 2:
msg = "Autorisierung Kein ungültiger Speicherplatz"
raise exceptions.AuthenticationFailed(msg)
try:
jwt_token = auth[1]
jwt_info = jwt.decode(jwt_token, SECRET_KEY)
userid = jwt_info.get("userid")
try:
user = UserInfo.objects.get(pk=userid)
user.is_authenticated = True
return (user, jwt_token)
except:
msg = "Benutzer existiert nicht"
raise exceptions.AuthenticationFailed(msg)
except jwt.ExpiredSignatureError:
msg = "Token ist Timeout"
raise exceptions.AuthenticationFailed(msg)
def authenticate_header(self, request):
pass
Die Klasse enthält eine Authentifizierungsmethode. Wenn die Authentifizierung erfolgreich ist, wird ein Tupel mit Benutzerinformationen zurückgegeben. Damit ist die Analyse der loginbezogenen Quellen abgeschlossen.
Vielen Dank, dass Sie bis zum Ende bei uns bleiben. : raise_hand_tone1:
Recommended Posts