На даний момент я активно працюю над програмою, яка буде працювати з REST API сайту на Django. І одним з перших кроків було налаштування аутентифікації користувача за токеном, але для того, щоб це запрацювало, потрібно спочатку отримати токен авторизації.
Розгляньмо, як це можна зробити.
Установка Django Rest Framework
Оскільки це найперша стаття із застосування DRF, то опишу докладніший процес встановлення та налаштування DRF. У Подальшому я вже не наводитиму цих інструкцій.
Встановлюємо DRF та інші необхідні пакети
pip install djangorestframework pip install markdown # Markdown support for the browsable API. pip install django-filter
Далі додаємо програму 'rest_frameword' в INSTALLED_APPS у файлі конфігурації сайту settings.py
INSTALLED_APPS = [ ... 'rest_framework', ]
Далі офіційна документація пропонує підключити в urls.py файлі login та logout View із rest_framework, щоб можна було зручно користуватися API у браузері.
Якщо чесно, то я не використовую це API, оскільки мені зручніше користуватися документацією, що згенерована через swagger, про що я теж скажу далі, але я все одно підключаю дані View, щоб потім не вирішувати випадкові проблеми.
urlpatterns = [ ... path('api-auth/', include('rest_framework.urls')), ]
Далі налаштовуємо класи автентифікації та прав доступу за замовчуванням (також у settingsp.py)
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework.authentication.BasicAuthentication', 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.TokenAuthentication', ], 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.IsAuthenticated', ], }
Тепер все готове, щоб написати точку доступу для отримання токена. Але попередньо я хочу підключити ще й генерування swagger документації. Просто так зручніше працювати, мені, наприклад, дуже подобається документація redoc, в якій досить красиво і зручно все відображається.
Установка Swagger
А зараз одразу підключимо swagger на сайті. Я розумію, що це не відноситься до теми статті, але в коді я роблю спеціальні маніпуляції, щоб підключити спеціальне відображення документації і вважаю, що надалі це може стати Вам у нагоді, оскільки:
- Ви будете надалі використовувати swagger
- Вам доведеться іноді кастомізувати виведення інформації в описі API, а саме для токена у мене була найспецифічніша зміна для swagger.
Установим drf-yasg
Для цього керуючись документацією виконаємо наступну команду
pip install -U drf-yasg
Після цього модифікуємо файл settings.py
INSTALLED_APPS = [ ... 'django.contrib.staticfiles', # required for serving swagger ui's css/js files 'drf_yasg', ... ]
А тепер зареєструємо swagger в urls сайту
from django.urls import re_path from drf_yasg import openapi from drf_yasg.views import get_schema_view from rest_framework import permissions schema_view = get_schema_view( openapi.Info( title="EXAMPLE API", default_version='v1', description="REST API Documentation", contact=openapi.Contact(email="example@example.com"), ), public=True, permission_classes=(permissions.IsAdminUser,), ) urlpatterns = [ ... re_path(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'), re_path(r'^swagger/$', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'), re_path(r'^redoc/$', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'), ]
Якщо ви уважно подивіться на код, побачите, що я зареєстрував swagger тільки для адміністрації сайту. Якщо хочете, щоб документація була відкритою, видаліть цей рядок
permission_classes=(permissions.IsAdminUser,),
Додатково можна додати інформацію у виведення документації про те, які типи автентифікації використовуються для API. Це виконується у файлі settings.py.
SWAGGER_SETTINGS = { 'SECURITY_DEFINITIONS': { 'Basic': { 'type': 'basic' }, 'Bearer': { 'type': 'apiKey', 'name': 'Authorization', 'in': 'header' } } }
Ось тепер можна приступити до реалізації точки доступу для отримання токена.
Додаток API
Створимо програму api, в якій буде додано кінцеву точку для отримання токена.
python manage.py startapp api
serializers.py
Далі створимо файл із серіалізаторами, в якому буде створено спеціальний серіалізатор, який описуватиме відповідь сайту в swagger.
# -*- coding: utf-8 -*- from rest_framework import serializers class Response201AuthTokenSerializer(serializers.Serializer): token = serializers.CharField(required=True, allow_blank=False) user_id = serializers.IntegerField(required=True)
Цей серіалізатор коректно генеруватиме інформацію про відповідь у документації, і я її використовую для створення JSON відповіді з токеном.
views.py
Після чого модифікує файл views.py, щоб отримати кінцеву точку.
# -*- coding: utf-8 -*- from django.contrib.auth import get_user_model from django.http import JsonResponse from django.utils.translation import gettext_lazy as _ from drf_yasg import openapi from drf_yasg.utils import swagger_auto_schema from rest_framework import authentication, viewsets from rest_framework.authtoken.views import ObtainAuthToken from api.serializers import Response201AuthTokenSerializer class CustomAuthToken(ObtainAuthToken): authentication_classes = [authentication.BasicAuthentication] @swagger_auto_schema(responses={ "201": openapi.Response( description=_("User has got Token"), schema=Response201AuthTokenSerializer, ) }) def post(self, request, *args, **kwargs): serializer = self.serializer_class(data=request.data, context={'request': request}) serializer.is_valid(raise_exception=True) user = serializer.validated_data['user'] token, created = Token.objects.get_or_create(user=user) response201 = Response201AuthTokenSerializer(data={"token": token.key, "user_id": user.pk}) response201.is_valid(raise_exception=True) return JsonResponse(response201.data)
Як бачите в коді є кастомізована схема swagger відповіді 201, контент створений. З серіалізатора Response201AuthTokenSerializer буде сформовано коректну документацію.
Крім іншого я використовую Response201AuthTokenSerializer, щоб сфомувати відповідь з токеном, а також id користувача. Надалі я використовую ID користувача для маніпуляції з даними в мобільному додатку.
Відмінним нюансом даного view є те, що як аутентифікація використовується лише BasicAuthenttication, тобто користувач отримує доступ до даного view тільки через username та password. Надалі розробка API ведеться від використання токена.
urls.py
А тепер підключити view для отримання токена у файлах urls
# -*- coding: utf-8 -*- from django.urls import path from api import views app_name = 'api' urlpatterns = [ path('api-token-auth/', views.CustomAuthToken.as_view()), ]
У цьому файлі визначаємо ім'я програми, що використовується для формування маршрутів, тобто api. Також підключаємо view токена до маршрутизації.
І в кінці підключаємо urls.py програми api в основному файлі urls.py всього проекту.
urlpatterns = [ ... path('api/', include('api.urls')), ... ]
Тепер, щоб отримати токен, необхідно направити POST запит по URL http://127.0.0.1/api/api-token-auth/**, в тому випадку, щоб тестувати функціонал на локальному сервері. У разі бойового сервера потрібно надсилати запит на адресу з доменом вашого сайту.
Для аутентифікації необхідно використовувати Basic аутентифікацію.
Приклад запиту маркера в Felgo QML
Ось приклад коду для запиту токена у додатку написаному на QML Felgo
function login(username, password, success, error) { HttpRequest .post("http://127.0.0.1/api/api-token-auth/", {username: username, password: password}) .timeout(5000) .set('Content-Type', 'application/json') .then(function(res) { success(res) }) .catch(function(err) { error(err) }); }
Доброго времени.
А если кастомный юзер.
И активация юзера подтверждением по смс или звонку?
Добрый день
Если Вы имеетe ввиду, что модель пользователя наследована от AbstractUser и переопределена для проекта, то да - этот пример рабочий, я сейчас занимаюсь одним проектом, который будет иметь приложение и использую там кастомного пользователя.
А что касается подтверждения по СМС, то я участвовал несколько лет назад в проекте, где было подтверждение по СМС. Код показать не могу, но суть была в том, что там было два REST API View, сначало приложение стучалось на первый url, куда посылало логин и пароль, при получении ответа 200, приложение меняло форму ввода данных и ждало, пока пользователь заполнит код из СМС и подтвердит отправку. В этом случае отправка кода была уже на второй url, который проверял правильность кода, и уже в этом случае отдавал токен.
Естественно первый URL, который обрабатывал логин и пароль, стучался на API стороннего провайдера по отправке СМС, получал отправленный код и сохранял в отдельную таблицу, чтобы потом сравнить код и соответствие пользователя коду.
В моем случае кастом от AbstractBaseUser
Только токен я использую knox(Стандарт мобильной безопастности Samsung), потому и спросил
Дальше понятно:
Регистрация post на страницу урл api/register(можно сразу отправить запрос на звонок, после создания пользователя)
Если удачно то получим 4-x символьный код от провайдера, запищем его. Если неудачно то создаем свой и шлем смс
Cледом post-запрос на верификацию с кодом(при удаче - активируем пользователя, при не удаче 4 попытки на повтор)
В таком случае без напильника этот код сходу не взлетит, если конкретно knox нужно использовать.
А касательно самого AbstractBaseUser, то должно заработать.