Même si vous ne regardez pas le contenu jusqu'à présent, vous pouvez comprendre le contenu de cette fois, donc j'espère que vous pourrez rester en contact avec moi jusqu'à la fin. : détendu:
Il s'agit d'une abréviation de JSON Web Token. Il est possible de conserver des informations arbitraires (revendications) dans le token. Par exemple, le serveur génère un token contenant les informations "Logged as administrator" pour le client. être capable de. Le client peut utiliser le jeton pour prouver qu'il est connecté en tant qu'administrateur. -[Wikipédia] (https://ja.wikipedia.org/wiki/JSON_Web_Token)
Vous pouvez facilement implémenter la connexion JWT en utilisant la bibliothèque django-rest-framework-jwt. Il est plus facile de le personnaliser de différentes manières si vous l'écrivez directement, alors écrivez-le directement.
pip install Django
pip install djangorestframework
pip install markdown
pip install django-filter
django-admin startproject jwttest
cd jwttest
python manage.py runserver
Si vous démarrez le serveur et voyez la fusée normalement, tout va bien.
Créez une nouvelle application.
python manage.py startapp api
Ajoutez-le à ʻINSTALLED_APPS avec
rest_framework`.
jwttest/settings.py
INSTALLED_APPS = [
...
'rest_framework',
'api'
]
Créez un modèle d'utilisateur pour la connexion.
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)
Exécutez la migration de base de données.
python manage.py makemigrations
python manage.py migrate
Installez la bibliothèque pour la génération de jetons JWT.
pip install pyjwt
Ajouter une classe pour la connexion,
Ajoutez le dossier ʻutls sous le répertoire ʻapi
, et ajoutez un nouveau fichier ʻauth.py` à l'intérieur.
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('Échec d'authentification')
elif user_obj.password != password:
raise exceptions.AuthenticationFailed('Je n'ai pas de mot de passe')
token = generate_jwt(user_obj)
return (token, None)
def authenticate_header(self, request):
pass
#Générez un jeton avec la bibliothèque jwt que vous venez d'installer
#Le contenu du jeton comprend les informations utilisateur et le délai d'expiration
#Il est fixe que la clé de temporisation est exp
#document: 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")
Ajoutez également une vue pour la connexion.
Si la connexion réussit, JWT est renvoyé.
Ajoutez le NormalAuthentication
créé précédemment à ʻauthentication_classes`.
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})
Ajouter l'URL.
jwttest/urls.py
...
from api.views import Login
urlpatterns = [
...
path('login/', Login.as_view()),
]
Ajoutez une information utilisateur![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)
Démarrez le serveur et essayez de vous connecter.
Analysons le JWT retourné avec https: // jwt.io /
.
Le JWT contient les informations que vous avez spécifiées.
Créez une vue que vous ne pouvez voir que si vous êtes connecté et utilisez ce jeton pour y accéder.
Tout d'abord, ajoutez la classe d'authentification pour JWT à ʻapi / utils / auth.py`.
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 = "Autorisation désactivée"
raise exceptions.AuthenticationFailed(msg)
elif len(auth) > 2:
msg = "Autorisation Pas d'espace non valide"
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 = "L'utilisateur n'existe pas"
raise exceptions.AuthenticationFailed(msg)
except jwt.ExpiredSignatureError:
msg = "le jeton a expiré"
raise exceptions.AuthenticationFailed(msg)
def authenticate_header(self, request):
pass
...
Ajout de vues à ʻapi / views.py` qui ne sont pas accessibles sans connexion.
api/views.py
...
from rest_framework.permissions import IsAuthenticated
...
class Something(APIView):
authentication_classes = [JWTAuthentication, ]
#Rendez-le accessible uniquement aux utilisateurs connectés.
permission_classes = [IsAuthenticated, ]
def get(self, request, *args, **kwargs):
return Response({"data": "C'est le contenu"})
...
J'essaierai d'y accéder après avoir ajouté l'url.
python:jwttest:urls.py
path('data/', Something.as_view())
Tout d'abord, accédez sans Token. Il a renvoyé «les informations d'authentification n'ont pas été fournies».
Après avoir ajouté le jeton, j'ai pu y accéder.
C'est tout, mais j'aimerais ajouter une analyse du code source lié à la connexion du framework Django REST. Veuillez lire si vous êtes intéressé. : détendu:
Je vais analyser en fonction du code que j'ai écrit plus tôt,
CBV (Vues basées sur les classes) Si utilisé, dispatch
sera exécuté.
Avec cela comme entrée, nous examinerons le code source.
Pour voir les choses, ajoutez self.dispatch ()
à la classe de connexion que j'ai écrite plus tôt.
api/view.py
...
class Login(APIView):
authentication_classes = [NormalAuthentication, ]
def post(self, request, *args, **kwargs):
#Ajoutez et suivez le code source
#Lors de l'utilisation de PyCharm
#commande sur mac+Cliquez sur
#Alt en victoire+Devrait être un clic
self.dispatch()
return Response({"token": request.user})
...
La destination est def dispatch (self, request, * args, ** kwargs):
à la ligne 481 de rest_framework / views.py
.
Regardons le contenu de la fonction ʻinitialize_request` à la ligne 488.
rest_framework/views.py
def dispatch(self, request, *args, **kwargs):
...
#Regardons le contenu de cette fonction
request = self.initialize_request(request, *args, **kwargs)
self.request = request
La définition du contenu est à la ligne 381 de 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(),
#ici
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
Et si vous regardez le contenu de self.get_authenticators ()
à la ligne 390,
J'ai le code suivant, qui est tiré de self.authentication_classes
quelle est la classe d'authentification utilisant le CBV correspondant.
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]
Si vous suivez la définition de self.authentication_classes
,
La ligne 109 de rest_framework / views.py
a la définition suivante:
rest_framework/views.py
class APIView(View):
...
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
Par conséquent, il existe deux endroits où vous pouvez définir directement la classe d'authentification à utiliser.
CBV
héritée de ʻAPIView`api/views.py
...
class Login(APIView):
#ici
authentication_classes = [NormalAuthentication, ]
def post(self, request, *args, **kwargs):
return Response({"token": request.user})
...
REST_FRAMEWORK
dans settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': ['api.utils.auth.NormalAuthentication']
}
Une fois que vous avez compris la relation entre CBV et la classe d'authentification, examinons les fonctions de la classe d'authentification.
Nous suivrons également de dispatch
, self.initial (request, * args, ** kwargs) ʻa la ligne 493 de
rest_framework / views.py`.
rest_framework/views.py
def dispatch(self, request, *args, **kwargs):
...
try:
self.initial(request, *args, **kwargs)
...
J'en suivrai la définition. Ligne 395 de rest_framework / views.py
.
Il y a perform_authentication
, nous irons plus loin.
python:rest_framework.py/views.py
...
def initial(self, request, *args, **kwargs):
...
self.perform_authentication(request)
...
Au-delà de cela, il y a «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
...
Sa définition est à la ligne 213 de 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
...
Jetons un œil à la définition de self._authenticate ()
. Ligne 366 de rest_framework / request.py
.
Le contenu consiste à extraire la classe de la liste des classes d'authentification CBV et à exécuter la méthode ʻauthenticate` de cette classe.
Le résultat de l'exécution est un «tuple» qui contient deux éléments, le premier des tuples est «self.user» et le second est «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()
Dans cet esprit, jetons un coup d'œil à la classe d'authentification pour JWT définie précédemment.
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 = "Autorisation désactivée"
raise exceptions.AuthenticationFailed(msg)
elif len(auth) > 2:
msg = "Autorisation Pas d'espace non valide"
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 = "L'utilisateur n'existe pas"
raise exceptions.AuthenticationFailed(msg)
except jwt.ExpiredSignatureError:
msg = "le jeton est expiré"
raise exceptions.AuthenticationFailed(msg)
def authenticate_header(self, request):
pass
La classe contient une méthode ʻauthenticate`. Si l'authentification réussit, un tuple contenant des informations utilisateur est renvoyé. Ceci conclut l'analyse des sources liées à la connexion.
Merci de rester avec nous jusqu'à la fin. : lift_hand_tone1:
Recommended Posts