[PYTHON] Erstellen Sie eine API für die Benutzerauthentifizierung mit Django REST Framework

Ich habe die folgende API mit Django REST Framework erstellt. Machen Sie sich also eine Notiz.

--Einloggen --Benutzer erstellt

Obwohl ich es gemacht habe, ist der Teil, den ich mit einer relativ großen Atmosphäre gemacht habe, groß, und es gibt auch das Problem, ob dies optimal ist, so dass es nur als Referenz dient.

Modell erstellen

Sie können das Standardbenutzermodell für das Modell verwenden. Wenn Sie jedoch eine tatsächliche Anwendung erstellen möchten, müssen Sie diese anpassen. Daher habe ich das folgende Modell erstellt.

user/models.py


from django.db import models
from django.contrib.auth.models import (
    BaseUserManager, AbstractBaseUser, _user_has_perm
)
from django.core import validators
from django.utils.translation import ugettext_lazy as _
from django.utils import timezone


class AccountManager(BaseUserManager):
    def create_user(self, request_data, **kwargs):
        now = timezone.now()
        if not request_data['email']:
            raise ValueError('Users must have an email address.')

        profile = ""
        if request_data.get('profile'):
            profile = request_data['profile']

        user = self.model(
            username=request_data['username'],
            email=self.normalize_email(request_data['email']),
            is_active=True,
            last_login=now,
            date_joined=now,
            profile=profile
        )

        user.set_password(request_data['password'])
        user.save(using=self._db)
        return user

    def create_superuser(self, username, email, password, **extra_fields):
        request_data = {
            'username': username,
            'email': email,
            'password': password
        }
        user = self.create_user(request_data)
        user.is_active = True
        user.is_staff = True
        user.is_admin = True
        user.save(using=self._db)
        return user


class Account(AbstractBaseUser):
    username    = models.CharField(_('username'), max_length=30, unique=True)
    first_name  = models.CharField(_('first name'), max_length=30, blank=True)
    last_name   = models.CharField(_('last name'), max_length=30, blank=True)
    email       = models.EmailField(verbose_name='email address', max_length=255, unique=True)
    profile     = models.CharField(_('profile'), max_length=255, blank=True)
    is_active   = models.BooleanField(default=True)
    is_staff    = models.BooleanField(default=False)
    is_admin    = models.BooleanField(default=False)
    date_joined = models.DateTimeField(_('date joined'), default=timezone.now)

    objects = AccountManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['username']

    def user_has_perm(user, perm, obj):
        return _user_has_perm(user, perm, obj)

    def has_perm(self, perm, obj=None):
        return _user_has_perm(self, perm, obj=obj)

    def has_module_perms(self, app_label):
        return self.is_admin

    def get_short_name(self):
        return self.first_name

    @property
    def is_superuser(self):
        return self.is_admin

    class Meta:
        db_table = 'api_user'
        swappable = 'AUTH_USER_MODEL'

Der Administrator kann wie gewohnt mit "$ python manage.py createduperuser" erstellt werden. Die folgenden zwei Punkte unterscheiden sich vom Standard.

  1. Ändern Sie das Feld, in dem das Kennwort zum Anmelden kombiniert wird, vom Benutzernamen in die E-Mail Dies wird im folgenden Teil angewendet.
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
  1. Fügen Sie ein Feld hinzu, um ein Profil einzugeben (Profil)
profile     = models.CharField(_('profile'), max_length=255, blank=True)

das ist alles.

Implementierte API für die Anmeldung

Dieses Mal haben wir die Token-Authentifizierung durch JWT implementiert. Installieren Sie django-rest-framework-jwt mit pip.

$ pip install djangorestframework-jwt

Fügen Sie nach der Installation Folgendes zu settings.py hinzu.

djangoproject/settings.py


JWT_AUTH = {
    'JWT_VERIFY_EXPIRATION': False,
    'JWT_AUTH_HEADER_PREFIX': 'JWT',
}


REST_FRAMEWORK = { 
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),  
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
    ),  
    'NON_FIELD_ERRORS_KEY': 'detail',
    'TEST_REQUEST_DEFAULT_FORMAT': 'json'
}

Wenn Sie "JWT_VERIFY_EXPIRATION" auf "False" setzen, ist das Ablaufdatum des Tokens dauerhaft.
Gehen Sie als Nächstes wie folgt zu url.py.

djangoproject/urls.py


from django.conf.urls import url

from rest_framework_jwt.views import obtain_jwt_token

urlpatterns = [
    url(r'^login/', obtain_jwt_token),
]

Allein damit können Sie ein Token erhalten, indem Sie per E-Mail und Passwort an / login senden.

Implementieren Sie eine vom Benutzer erstellte API

URL hinzufügen

Zunächst benötigen wir einen API-Endpunkt, also erstellen Sie urls.py in der Anwendung und

user/urls.py


from django.conf.urls import include, url
from rest_framework import routers
from .views import AuthRegister

urlpatterns = [
    url(r'^register/$', AuthRegister.as_view()),
]

Laden Sie es auf der Projektseite in urls.py.

djangoproject/urls.py


from django.conf.urls import include, url
from django.contrib import admin

from rest_framework_jwt.views import obtain_jwt_token
urlpatterns = [
    url(r'^login/', obtain_jwt_token),
    url(r'^api/', include('authentication.urls')),
]

POST an / api / register /, um die Benutzererstellung zu ermöglichen

Ansicht erstellen

user/views.py


from django.contrib.auth import authenticate
from django.db import transaction
from django.http import HttpResponse, Http404
from rest_framework import authentication, permissions, generics
from rest_framework_jwt.settings import api_settings
from rest_framework.exceptions import AuthenticationFailed
from rest_framework.response import Response
from rest_framework import status, viewsets, filters
from rest_framework.views import APIView
from .serializer import AccountSerializer
from .models import Account, AccountManager

#Vom Benutzer erstellte Ansicht(POST)
class AuthRegister(generics.CreateAPIView):
    permission_classes = (permissions.AllowAny,)
    queryset = Account.objects.all()
    serializer_class = AccountSerializer

    @transaction.atomic
    def post(self, request, format=None):
        serializer = AccountSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Mithilfe von Generika können Sie die HTTP-Methoden einschränken, die eine Klasse akzeptieren kann. Weitere Informationen zu Generika finden Sie hier (http://www.django-rest-framework.org/api-guide/generic-views/). CreateAPIView wird nur für Endpunkte zum Erstellen verwendet.

Natürlich ist es für die Benutzererstellung auch erforderlich, auf den Endpunkt zu POSTEN, auch wenn dieser nicht authentifiziert ist. Daher wird allow_classes = (permissions.AllowAny,) festgelegt.

Erstellen eines Serializers

from django.contrib.auth import update_session_auth_hash
from rest_framework import serializers

from .models import Account, AccountManager


class AccountSerializer(serializers.ModelSerializer):
    password = serializers.CharField(write_only=True, required=False)

    class Meta:
        model = Account
        fields = ('id', 'username', 'email', 'profile', 'password')

    def create(self, validated_data):
        return Account.objects.create_user(request_data=validated_data)

Grob gesagt fühlt es sich an, als würde man eine vom Benutzer erstellte Methode aufrufen, die in Model definiert ist.

Wenn Sie im obigen Zustand E-Mail, Passwort, Profil (optional) an / api / register / senden, wird vorerst ein Benutzer erstellt.

Informationen zum angemeldeten Benutzer abrufen

Die Erfassung von Benutzerinformationen hängt von der Anwendung ab. Derzeit kann der angemeldete Benutzer jedoch nur seine eigenen Informationen erfassen. Wenn Sie Informationen zu anderen Benutzern erhalten möchten, müssen Sie eine andere Ansicht und einen anderen Endpunkt erstellen. Es tut mir leid.

Bearbeiten von urls.py

Bearbeiten Sie urls.py auf der Anwendungsseite.

user/urls.py


from django.conf.urls import include, url
from rest_framework import routers
from .views import AuthRegister, AuthInfoGetView

urlpatterns = [
    url(r'^register/$', AuthRegister.as_view()),
    url(r'^mypage/$', AuthInfoGetView.as_view()),
]

Erhalten Sie Benutzerinformationen, wenn Sie ein GET nach / api / mypage werfen.

Ansicht bearbeiten

Fügen Sie views.py zuvor Folgendes hinzu

user/views.py


#Ansicht der Benutzerinformationserfassung(GET)
class AuthInfoGetView(generics.RetrieveAPIView):
    permission_classes = (permissions.IsAuthenticated,)
    queryset = Account.objects.all()
    serializer_class = AccountSerializer

    def get(self, request, format=None):
        return Response(data={
            'username': request.user.username,
            'email': request.user.email,
            'profile': request.user.profile,
            },
            status=status.HTTP_200_OK)

RetrieveAPIView ist ein Endpunkt für die GET-Methode. Da ich versuche, meine eigenen Informationen abzurufen, versuche ich auch, sie nur abzurufen, wenn ich mit allow_classes = (permissions.IsAuthenticated,) angemeldet bin.

Fügen Sie in diesem Status "{'Content-Type': 'application / json', 'Authorization': 'JWT [beim Anmelden erhaltenes Token' '}" zum Header hinzu und werfen Sie die GET-Methode, um sich anzumelden. Sie können den Benutzernamen / die E-Mail-Adresse / das Profil des aktuellen Benutzers abrufen.

Aktualisierte Login-Benutzerinformationen (einschließlich Passwort-Update)

Es ist die Rede davon, ob beim Aktualisieren von Informationen PUT oder PATCH verwendet werden soll, aber vorerst habe ich diesmal PUT verwendet, aber jetzt, wo ich darüber nachdenke, denke ich, dass PATCH gut ist. Da ich es jedoch geschafft habe, werde ich in PUT darüber sprechen.

Bearbeiten von urls.py

Erstellen Sie einen Endpunkt mit dem Namen / auth_update und rufen Sie die Ansicht AuthInfoUpdateView auf.

user/urls.py


from django.conf.urls import include, url
from rest_framework import routers
from .views import AuthRegister, AuthInfoGetView, AuthInfoUpdateView

urlpatterns = [
    url(r'^register/$', AuthRegister.as_view()),
    url(r'^mypage/$', AuthInfoGetView.as_view()),
    url(r'^auth_update/$', AuthInfoUpdateView.as_view()),
]

Ansicht bearbeiten

Fügen Sie views.py Folgendes hinzu. Dies ist eine Implementierung von AuthInfoUpdateView, eine Ansicht, die aufgerufen wird, wenn sich in / auth_update ein PUT befindet. Da E-Mail als Schlüssel verwendet wird, muss die E-Mail des angemeldeten Benutzers beim Senden eines PUT auch im JSON enthalten sein.

user/views.py


#Ansicht der Aktualisierung der Benutzerinformationen(PUT)
class AuthInfoUpdateView(generics.UpdateAPIView):
    permission_classes = (permissions.IsAuthenticated,)
    serializer_class = AccountSerializer
    lookup_field = 'email'
    queryset = Account.objects.all()

    def get_object(self):
        try:
            instance = self.queryset.get(email=self.request.user)
            return instance
        except Account.DoesNotExist:
            raise Http404

Wie der Name schon sagt, akzeptiert UpdateAPIView PUT / PATCH als reine Update-Ansicht.

Serializer bearbeiten

Bearbeiten Sie AccountSerializer in serializers.py wie folgt.

user/serializers.py


class AccountSerializer(serializers.ModelSerializer):
    password = serializers.CharField(write_only=True, required=False)

    class Meta:
        model = Account
        fields = ('id', 'username', 'email', 'profile', 'password')

    def create(self, validated_data):
        return Account.objects.create_user(request_data=validated_data)

    def update(self, instance, validated_data):
        if 'password' in validated_data:
            instance.set_password(validated_data['password'])
        else:
            instance = super().update(instance, validated_data)
        instance.save()
        return instance

Wenn das Kennwort aktualisiert wird, muss das empfangene Kennwort gehasht werden. Verwenden Sie daher die Methode set_password. Wie beim Abrufen von Benutzerinformationen müssen Sie im Header "{'Content-Type': 'application / json', 'Authorization': 'JWT [Token beim Anmelden erhalten]'}" eingeben.

User Löschung

Schließlich werden wir das Löschen des angemeldeten Benutzers implementieren.

Bearbeiten von urls.py

Ich erstelle einen Endpunkt namens / delete und rufe AuthInfoDeleteView auf.

user/urls.py


from django.conf.urls import include, url
from rest_framework import routers
from .views import AuthRegister, AuthInfoGetView, AuthInfoUpdateView, AuthInfoDeleteView

urlpatterns = [
    url(r'^register/$', AuthRegister.as_view()),
    url(r'^mypage/$', AuthInfoGetView.as_view()),
    url(r'^auth_update/$', AuthInfoUpdateView.as_view()),
    url(r'^delete/$', AuthInfoDeleteView.as_view()),
]

Ansicht bearbeiten

Eine Implementierung von AuthInfoDeleteView.

user/views.py


#Benutzer löschen Ansicht(DELETE)
class AuthInfoDeleteView(generics.DestroyAPIView):
    permission_classes = (permissions.IsAuthenticated,)
    serializer_class = AccountSerializer
    lookup_field = 'email'
    queryset = Account.objects.all()

    def get_object(self):
        try:
            instance = self.queryset.get(email=self.request.user)
            return instance
        except Account.DoesNotExist:
            raise Http404

Durch Festlegen von "generics.DestroyAPIView" akzeptiert die Ansicht nur die DELETE-Methode. Durch Senden von DELETE mit "{'Content-Type": "application / json", "Authorization": "JWT [Token beim Anmelden erhalten]"} "im Header sowie durch Erfassen und Aktualisieren von Benutzerinformationen Sie können den angemeldeten Benutzer löschen.

das ist alles.

Probleme

Tatsächlich kann die E-Mail im aktuellen Status nicht aktualisiert werden. Nein, ich kann es tun, aber da das Token, das ich auf der Clientseite habe, mit der alten E-Mail angemeldet ist, ist das Verhalten seltsam, wenn auf der Clientseite das mit der neuen E-Mail erhaltene Token nicht vorhanden ist. Sie können ein neues Token mit einer neuen E-Mail ausstellen, indem Sie mit einem Kennwort und einer neuen E-Mail an / login senden, aber das ist Unsinn. Sie müssen das Passwort auf der Clientseite im Klartext haben. Ich möchte dies vorerst etwas genauer untersuchen.

Ich denke auch, dass es notwendig ist, eine API für die Neuausgabe des Passworts vorzubereiten, um das Passwort zu vergessen, aber das war ärgerlich </ s>, also habe ich beschlossen, es diesmal nicht zu tun.

Das offensichtliche Problem besteht auch darin, dass die Benutzerinformationen leicht manipuliert oder gelöscht werden können, wenn das Anmeldetoken auf irgendeine Weise erhalten wird. Ich denke jedoch, dass das Problem des böswilligen Raubes von Token eine Angelegenheit von JWT ist. Dieses Mal ist das Ablaufdatum des Tokens unendlich, aber ich frage mich, ob es notwendig ist, ein Ablaufdatum festzulegen oder ein Aktualisierungstoken auszugeben, wenn eine Anforderung an die API gesendet wird, wenn die Anwendung tatsächlich veröffentlicht wird. Ich denke.

Darüber hinaus ist die oben genannte API in Kombination mit Angular auf der Vorderseite im folgenden Repository verfügbar. https://github.com/xKxAxKx/auth_django_and_angular2

Recommended Posts

Erstellen Sie eine API für die Benutzerauthentifizierung mit Django REST Framework
Erstellen Sie eine RESTful-API mit dem Django Rest Framework
Implementierung der Authentifizierungsfunktion in Django REST Framework mit djoser
Implementierung der benutzerdefinierten Authentifizierungsfunktion für Benutzermodelle in Django REST Framework mit djoser
Django REST Framework mit Vue.js
Melden Sie sich mit dem Django Rest Framework an
Erstellen Sie eine Todo-App mit Django REST Framework + Angular
[Django] Verwenden Sie MessagePack mit dem Django REST-Framework
CRUD POST mit Nuxt & Django REST Framework
CRUD GET mit Nuxt & Django REST Framework ①
Erstellen Sie eine REST-API, um dynamodb mit dem Django REST Framework zu betreiben
CRUD PUT, DELETE mit Nuxt & Django REST Framework
Grundlagen des Django REST-Frameworks
Tipps zum Django Rest Framework
Wenn Sie mit dem Django REST-Framework filtern möchten
Implementieren Sie die API mit explosiver Geschwindigkeit mithilfe des Django REST Framework
Implementieren Sie hierarchische URLs mit drf-verschachtelten Routern im Django REST-Framework
Erstellen Sie eine API mit Django
Erstellen Sie eine Homepage mit Django
Django REST Framework Stolperstein
Erstellen Sie mit Flask-AppBuilder ganz einfach Authentifizierung, Benutzerverwaltung und mehrsprachige Systeme
Erstellen Sie eine Authentifizierungsfunktion mit django-allauth und CustomUser in Django
Erstellen Sie eine Benutzerauthentifizierungsfunktion in Airflow
Implementierung der JWT-Authentifizierungsfunktion in Django REST Framework mit djoser
Implementierung von CRUD mithilfe der REST-API mit Python + Django Rest Framework + igGrid
Erstellen Sie mit Django einen Datei-Uploader
Wie man mit verstümmelten Charakteren in json von Django REST Framework umgeht
Logisches Löschen in Django, DRF (Django REST Framework)
Verstehen Sie den Komfort des Django Rest Framework
Ein Verwaltungstool, das sofort mit dem REST-Framework ng-admin + Django erstellt werden kann
Verschiedene Hinweise zum Django REST-Framework
Erstellen Sie mit Django Updateview einen Update-Bildschirm
Erstellen der ersten App mit Django Startprojekt
Überlegungen zum Design von Django REST Framework + Clean Architecture
Ich möchte eine API erstellen, die ein Modell mit einer rekursiven Beziehung im Django REST Framework zurückgibt
So generieren Sie automatisch ein API-Dokument mit dem Django REST-Framework und POST vom Dokumentbildschirm
Django: User Agent aufzeichnen und mit Admin verwalten
Erstellen Sie mit Django ein Dashboard für Netzwerkgeräte!
Erstellen Sie mit Docker eine Umgebung aus Nginx + uWSGI + Python (Django)
Django REST Framework Ein wenig nützlich zu wissen.
Erstellen Sie mit Django eine Hallo-Welt-Anwendung mit nur einer Datei
Implementieren Sie die JWT-Anmeldefunktion im Django REST-Framework
So erstellen Sie eine Rest-API in Django
Entwicklungspraxis für Webanwendungen: Erstellen Sie mit Django eine Seite zum Erstellen von Schichten! (Authentifizierungsverarbeitung)
Manchmal möchten Sie mit DRF (Django REST Framework) auf View information from Serializer zugreifen.