Django – #38 – REST API cz. 13 – Generowanie tokena dla istniejących użytkowników

Wprowadzenie.

W poprzednim wpisie przedstawiłem, w jaki sposób możemy zrealizować uwierzytelnianie przy pomocy tokena. Omawiany Token był wówczas tworzony w momencie tworzenia nowego konta. Wyobraźmy sobie taki przypadek, że posiadamy już aplikację, mamy zarejestrowanych użytkowników i chcemy wprowadzić dodatkową funkcjonalność w postaci tokena uwierzytelniającego. W związku z takim przypadkiem we wpisie przedstawiłem, w jaki sposób generować token dla aktualnych użytkowników oraz w jaki sposób użytkownik może pobrać swój token, żeby na przykład wprowadzić go do innej aplikacji korzystającej z naszego API.

Zakres artykułu.

  • Generowanie tokena dla istniejących użytkowników

Generowanie tokena dla istniejących użytkowników

W pierwszym kroku stwórzmy serializer dla modelu Token. Dodatkowo niech ten serializer będzie zawierał tylko jedno pole o nazwie key, ponieważ pole to zawiera tokeny użytkowników.

class TokenSerializer(serializers.ModelSerializer):
    class Meta:
        model = Token
        fields = ('key',)

Przejdźmy teraz do pliku views.py, gdzie zaimportujmy model Token oraz nowo stworzony serializer TokenSerializer

from django.contrib.auth.models import User
from django.db.models import query
from django.shortcuts import render
from rest_framework import generics, serializers
import rest_framework
from rest_framework import permissions
from .models import Author, Book, Borrow
from .serializers import AuthorSerializer, BookSerializer, BorrowSerializer, BorrowReturnBookSerializer, UserSerializer, TokenSerializer # new
from rest_framework.permissions import IsAuthenticated, BasePermission, SAFE_METHODS, IsAdminUser, IsAuthenticatedOrReadOnly, AllowAny
from rest_framework.exceptions import ValidationError
from django.utils import timezone
from rest_framework.authtoken.models import Token # new

W następnym kroku stwórzmy nową klasę widoku UserTokenList(), która będzie odpowiedzialna za zwracanie naszego tokena. W moim przypadku zastosowałem dziedziczenie po klasie generics.ListAPIView(), ponieważ wprowadzany adres nie zawiera numeru id z naszym tokenem. Użycie klasy ListAPIView() powoduje, że w odpowiedzi dostaniemy całą listę tokenów, dlatego w tym przypadku musimy napisać metodę get_queryset(), gdzie do modelu Token należy zastosować filtr po użytkowniku, który wysyła request. Drugą modyfikacją klasy, którą należy przeprowadzić jest nadpisanie metody get(). W tym przypadku musimy sprawdzić, czy nasz użytkownik znajduje się w bazie danych użytkowników, jeżeli użytkownik istnieje, wówczas sprawdzamy, czy dla naszego użytkonika w bazie danych jest wygenerowany token, jeżeli takiego tokenu nie ma, wówczas trzeba wykonać dodatkową czynność, czyli należy stworzyć token

class UserTokenList(generics.ListAPIView):
    queryset = Token.objects.all()
    serializer_class = TokenSerializer
    permission_classes = [IsAuthenticated]

    def get_queryset(self):
        return Token.objects.filter(user=self.request.user)

    def get(self, request, *args, **kwargs):
        user = User.objects.filter(username=self.request.user)
        if user.exists():
            token = Token.objects.filter(user=self.request.user)
            if token.exists():
                return self.list(request, *args, **kwargs)
            else:
                token = Token.objects.create(user=self.request.user)
                return self.list(request, *args, **kwargs)
        else:
            raise ValidationError('You are not signup')

Na koniec stwórzmy ścieżkę łączącą url z klasą widoku.

from django.contrib import admin
from django.urls import path, include
from restapiapp import views

urlpatterns = [
    path('admin/', admin.site.urls),

    # API
    path('api/authors/', views.AuthorList.as_view()),
    path('api/books/', views.BookList.as_view()),
    path('api/borrows/', views.BorrowList.as_view()),
    path('api/borrows/<int:pk>/', views.BorrowRetrieveDestroy.as_view()),
    path('api/borrows/<int:pk>/return/', views.BorrowReturnBookUpdate.as_view()),
    path('api/borrows/<int:pk>/edit/', views.BorrowRetrieveUpdate.as_view()),

    path('api/user/create', views.UserCreate.as_view()),
    path('api/user/login', views.UserTokenList.as_view()), # new

    # DRF
    path('api-auth/', include('rest_framework.urls')),
]

W tej chwili możemy przeprowadzić testy. W moim przypadku jak możecie zobaczyć mam dwa tokeny dla użytkownika Antek oraz Tomek.

Zaloguje się na konto Antka i przejdę pod adres 127.0.0.1:8000/api/user/login. Wynik, jaki otrzymałem zamieszczam poniżej.

Teraz tę samą procedurę przeprowadzę dla konta Tomka. Jak możemy zobaczyć, w jednym, jak i drugim przypadku wartości tokenów się zgadzają.

Na koniec sprawdźmy, jak zachowa się aplikacja, gdy zaloguję się na konto admina.

W odpowiedzi dostałem wartość klucza, która nie znajdowała się w bazie danych.

Sprawdźmy zatem, czy wartość tego klucza została wpisana do bazy danych. W tym celu należy przejść do panelu admina.

Jak widzimy, token został dodany do bazy danych i od teraz może zostać użyty przez inne aplikacje w celu uwierzytelniania naszego użytkownika.

Autor artykułu
Dominik Bednarski

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.