Написание пользовательского класса аутентификации в Django Rest Framework для работы с firebase
Предварительные требования
Если вы знаете, как настроить проект в Django Rest Framework и флаттер, и имеете некоторое базовое представление о REST API, тогда вам хорошо. Если вы хотите изучить основы Django / Flutter, перейдите к официальной документации по Django и Flutter и не стесняйтесь возвращаться к этой статье.
Введение
В этой статье исследуется способ написания пользовательского бэкэнда аутентификации для Django Rest Framework, который можно использовать для идентификации пользователей из вашего приложения flutter, которое использует firebase в качестве бэкэнда аутентификации. Приложение flutter подключается к серверу аутентификации firebase и проверяет пользователя. После проверки пользователя серверная часть аутентификации firebase возвращает токен идентификатора, который добавляется к каждому запросу в нашу серверную часть Django Rest. Наша настраиваемая серверная часть аутентификации проверяет токен идентификатора и идентифицирует пользователя.
Содержание:
- Создать проект фреймворка Django Rest
- Установите firebase-admin и настройте админский SDK на свой сервер
- Написание пользовательского класса аутентификации для Django Rest Framework
- Создание простой конечной точки API для тестирования реализации
- Создайте приложение Flutter
- Добавление firebase в приложение flutter
- Добавление FirebaseAuth и интеграция Django API в приложение
Создание проекта фреймворка Django Rest
Создайте проект Django и добавьте Django Rest Framework в настройки установленного приложения.
python -m venv .venv #Create a virtual environment if required
.venv\Scripts\activate #activate virtual environment on windows source .venv\bin\activate #activate virtual environment on Linux
#installing required libraries pip install django pip install djangorestframework pip install markdown pip install django-filter
pip install firebase-admin #Create Django project django-admin startproject firebaseauth #Add'rest_framework'
to yourINSTALLED_APPS
setting.INSTALLED_APPS = [ ... 'rest_framework', ]
#
Add the following to your rooturls.py
file. from django.urls import path,includeurlpatterns = [ ... path('api-auth/', include('rest_framework.urls')) ]
Установите firebase-admin и настройте административный SDK на своем сервере.
Перейдите в Firebase Console, нажмите Добавить проект, затем введите имя проекта и нажмите Продолжить. При необходимости вы можете включить Google Analytics для своего проекта. Нажмите Создать проект. После создания проекта перейдите в Настройки проекта ›Учетные записи служб и сгенерируйте новый закрытый ключ. Он будет использоваться административным SDK для связи с серверной частью firebase. Этот закрытый ключ должен храниться в надежном месте и не подлежит разглашению. В загруженном файле JSON есть сведения, необходимые для инициализации приложения. Чтобы позволить Admin SDK найти эти сведения, вы можете либо установить переменную среды GOOGLE_APPLICATION_CREDENTIALS, либо явно передать путь к ключу учетной записи службы в коде. Первый вариант более безопасен и настоятельно рекомендуется.
Дальнейшее чтение :
- Установка Django Rest Framework
- Работа с виртуальной средой на Python
- Создание проекта firebase
- Настройка firebase-admin
Написание пользовательского класса аутентификации для Django Rest Framework
Пакет dart для FirebaseAuth позволит нам иметь токен идентификатора, как только наш пользователь будет аутентифицирован в нашем приложении Flutter. Это веб-токен JSON, который можно проверить на стороне сервера для идентификации пользователя, отправляющего запрос. Мы будем отправлять токен ID с каждым запросом в заголовке Authorization
, а в нашем классе аутентификации мы будем использовать Firebase Admin SDK для проверки токена ID на нашем сервере DRF.
Давайте создадим новое приложение для управления пользователями и аутентификации. Если вы хотите, вы также можете использовать это приложение для расширения пользовательской модели по умолчанию.
python manage.py startapp auth
Создайте файл backends.py в приложении auth. Здесь мы будем писать наш собственный сервер аутентификации. Чтобы создать собственную схему аутентификации в DRF, мы создаем подкласс класса BaseAuthentication
и переопределяем метод authenticate()
. Метод аутентификации должен проверять учетные данные и возвращать кортеж (user,auth)
, если учетные данные проверены успешно, и None
в противном случае.
Получите токен Id из заголовка запроса, используя приведенный ниже код.
authorization_header = request.META.get("HTTP_AUTHORIZATION") id_token = authorization_header.split(" ").pop()
Вышеупомянутый идентификационный токен можно проверить с помощью приведенного ниже статуса.
decoded_token = auth.verify_id_token(id_token) uid = decoded_token['uid'] #get the unique user id
Мы можем сохранить этот uid
как первичный ключ в нашей модели пользователя, чтобы было легче идентифицировать пользователей на основе этого uid
.
В приведенном ниже коде показан последний файл «backends.py».
from django.contrib.auth.models import User from rest_framework import authentication from rest_framework import exceptions from firebase_admin import auth,initialize_app initialize_app() class FirebaseBackend(authentication.BaseAuthentication): def authenticate(self, request): authorization_header = request.META.get("HTTP_AUTHORIZATION") if not authorization_header: raise exceptions.AuthenticationFailed('Authorization credentials not provided') id_token = authorization_header.split(" ").pop() if not id_token: raise exceptions.AuthenticationFailed('Authorization credentials not provided') decoded_token = None try: decoded_token = auth.verify_id_token(id_token) except Exception: raise exceptions.AuthenticationFailed('Invalid ID Token') try: uid = decoded_token.get("uid") except Exception: raise exceptions.AuthenticationFailed('No such user exists') user, created = User.objects.get_or_create(username=uid) if((not user.first_name or not hasattr(user,'userprofile')) and not (request.method == 'PUT' and request.path.startswith("/api/users/"))): raise exceptions.PermissionDenied('User profile is incomplete. Please update the Profile Details') #allow users to make API calls only after profile is completed return (user, None)
Перейдите в корневой файл settings.py и добавьте следующие настройки, чтобы добавить наш собственный сервер аутентификации на наш сервер Django.
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'auth.backends.
FirebaseBackend', ] }
Дальнейшее чтение
Создание простой конечной точки API для тестирования реализации
Мы будем создавать сериализатор на основе модели User
в Django. Я создам другое приложение для конечной точки API. Добавьте еще одну модель с именем userprofile
, чтобы мы могли хранить некоторые дополнительные сведения, относящиеся к пользователю.
class UserProfile(models.Model): user = models.OneToOneField(User,on_delete=models.CASCADE) bio = models.CharField(max_length=200) dob = models.DateField()
Теперь нам нужно добавить сериализаторы и представления для этих моделей, чтобы к ним можно было получить доступ из API. Здесь используется простой ModelSerializer
. Обратите внимание, что мы должны переопределить update()
и create()
, поскольку ModelSerializer
не поддерживает запись во вложенные сериализаторы. Здесь перезаписывается только метод update()
, поскольку мы не используем прямой запрос API для создания пользователей.
class UserProfileSerializer(serializers.ModelSerializer): class Meta: model=UserProfile fields=['bio','dob'] class UserSerializer(serializers.ModelSerializer): userprofile = UserProfileSerializer() def update(self, instance,validated_data): if(not instance.username == self.context['request'].user.username): raise exceptions.PermissionDenied('You do not have permission to update') profile_data = validated_data.pop('userprofile') if(not hasattr(instance,'userprofile')): instance.userprofile = UserProfile.objects.create(user=instance,**profile_data) else: instance.userprofile.dob = profile_data["dob"] instance.userprofile.bio = profile_data["bio"] instance.userprofile.save() instance.first_name = validated_data.get('first_name',instance.first_name) instance.last_name = validated_data.get('last_name',instance.last_name) instance.email = validated_data.get('email',instance.email) instance.save() return instance class Meta: model = User fields = ['last_name','first_name','userprofile']
Чтобы сделать эти сериализаторы доступными через наш api, мы используем маршрутизатор по умолчанию в DRF вместе с ModelViewSet
#views.py from django.shortcuts import render from .serializers import UserSerializer from django.contrib.auth.models import User from rest_framework import viewsets class UserViewSet(viewsets.ModelViewSet): queryset = User.objects.all() serializer_class = UserSerializer lookup_field = 'username' #urls.py from django.urls import path, include from .views import UserViewSet from rest_framework import routers router =routers.DefaultRouter() router.register(r'users', UserViewSet) urlpatterns = [ path('', include(router.urls)), ]
Не забудьте включить этот файл URL-адресов в файл корневых URL-адресов.
Дальнейшее чтение:
Создайте приложение Flutter
Мы собираемся создать демонстрационное приложение Flutter с 3 экранами (вход / регистрация, данные профиля и главная). Я не буду вдаваться в подробности создания приложения flutter, но я добавлю исходный код в github.
Добавление firebase в приложение flutter
Подпишите свое приложение Flutter с помощью keytool в Android SDK. Теперь добавьте приложение flutter в проект firebase, который вы создали на одном из предыдущих шагов. Подпись необходима, чтобы мы могли получить подпись SHA, которая требуется для FirebaseAuth. Вы можете найти подробные инструкции в официальной документации.
После этого добавьте пакеты firebase_core и firebase_auth в pubspec.yaml
firebase_core: ^1.4.0 firebase_auth: ^3.0.1
Аутентификация и интеграция Django API в приложение
Экземпляр FirebaseAuth имеет метод userChanges()
, который возвращает поток, который можно прослушивать с помощью виджета Stream Builder. Это позволяет нам получать обновления об изменениях состояния аутентификации или изменении токена идентификатора (когда он обновляется и т. Д.).
Как только пользователь вошел в систему, вы можете использовать функцию getIdToken()
из firebase auth для получения токена идентификатора. Этот токен Id можно использовать для отправки запросов на ваш сервер DRF.
String id_token = await FirebaseAuth.instance.currentUser!.getIdToken(); http.put( Uri.parse("http://10.0.2.2:8000/api/users/" + FirebaseAuth.instance.currentUser!.uid + "/"), headers: { "Content-Type": "application/json", "Authorization":"Token " + id_token }, ..... )
Дальнейшее чтение:
Вы можете найти исходный код приложения flutter и бэкэнда Django на Github. Имейте в виду, что это не полное решение. В приложении можно многое улучшить, например, проверить вводимые данные и надлежащую обработку ошибок для вызовов API, а также методов регистрации и входа в систему. Он не был включен сюда для краткости статьи.
Надеюсь, эта статья вам помогла! Спасибо или читаю.