At the moment I am actively working on an application that will work with the REST API of a Django site. And one of the first steps was to set up user authentication by token, but in order for this to work, you must first obtain an authorization token.
Let's look at how this can be done.
Install Django Rest Framework
Since this is the very first article on using DRF, I will describe in more detail the process of installing and configuring DRF. In what follows, I will no longer give these instructions.
Install DRF and other necessary packages
pip install djangorestframework pip install markdown # Markdown support for the browsable API. pip install django-filter
Next, add the application 'rest_frameword' to INSTALLED_APPS in the site configuration file settings.py
INSTALLED_APPS = [ ... 'rest_framework', ]
Further, the official documentation suggests including the login and logout View from rest_framework in the urls.py file, so that you can conveniently use the API in the browser.
To be honest, I don’t use this API, because it’s more convenient for me to use the documentation generated through swagger, which I will also talk about later, but I still connect the View data so that I don’t solve random problems later.
urlpatterns = [ ... path('api-auth/', include('rest_framework.urls')), ]
Next, configure the default authentication and permission classes (also in 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', ], }
Now everything is ready in order to write an access point to receive a token. But first I want to connect the generation of swagger documentation. It’s just more convenient to work this way, for example, I really like the redoc documentation, in which everything is displayed quite beautifully and conveniently.
Installing Swagger
And now we will immediately connect swagger on the site. I understand that this is not related to the topic of the article, but in the code I do special manipulations to enable a special documentation display and I think that this may be useful to you in the future, because:
- You will use swagger in the future
- You will sometimes need to customize the output of information in the API description, namely for the token I had the most specific change for swagger.
Установим drf-yasg
To do this, following the documentation, run the following command
pip install -U drf-yasg
Then we modify the settings.py file
INSTALLED_APPS = [ ... 'django.contrib.staticfiles', # required for serving swagger ui's css/js files 'drf_yasg', ... ]
And now let's register swagger in the site 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'), ]
If you take a close look at the code, you will see that I registered the swagger only for the administration of the site. If you want the documentation to be open, then remove this line
permission_classes=(permissions.IsAdminUser,),
Optionally, you can add information to the documentation output about which authentication types are used for the API. This is done in the settings.py file.
SWAGGER_SETTINGS = { 'SECURITY_DEFINITIONS': { 'Basic': { 'type': 'basic' }, 'Bearer': { 'type': 'apiKey', 'name': 'Authorization', 'in': 'header' } } }
Now you can start implementing an access point to get a token.
Api application
Let's create an api application in which an endpoint will be added to receive a token.
python manage.py startapp api
serializers.py
Next, we will create a file with serializers, in which a special serializer will be created that will describe the site's response in 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)
This serializer will correctly generate the response information in the documentation, and I use it to generate a JSON response with a token.
views.py
Then we modify the views.py file to get the endpoint.
# -*- 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)
As you can see in the code there is a custom swagger schema for the 201 response, the content has been created. The correct documentation will be generated from the Response201AuthTokenSerializer serializer.
Among other things, I use the Response201AuthTokenSerializer to form a response with a token as well as a user id. In the future, I use the user id to manipulate data in a mobile application.
A distinctive nuance of this view is that only BasicAuthentication is used as authentication, that is, the user gets access to this view only through username and password. In the future, API development is underway to use the token.
urls.py
And now connect the view to get the token in the urls files
# -*- coding: utf-8 -*- from django.urls import path from api import views app_name = 'api' urlpatterns = [ path('api-token-auth/', views.CustomAuthToken.as_view()), ]
In this file, we define the name of the application that is used to generate routes, that is, api. We also connect the view of the token to the routing.
And at the end, we include the urls.py of the api application in the main urls.py file of the entire project.
urlpatterns = [ ... path('api/', include('api.urls')), ... ]
Now, in order to get a token, you need to send a POST request to the url http://127.0.0.1/api/api-token-auth/ , if you want to test the functionality on a local server. In the case of a combat server, you need to send a request to the address with the domain of your site.
For authentication, you need to use Basic authentication.
Example of token request in Felgo QML
Here is an example code for requesting a token in an application written in 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, то должно заработать.