Написание пользовательского класса аутентификации в 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-filterpip install firebase-admin #Create Django project django-admin startproject firebaseauth #Add'rest_framework'to yourINSTALLED_APPSsetting.INSTALLED_APPS = [ ... 'rest_framework', ]#Add the following to your rooturls.pyfile. 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, а также методов регистрации и входа в систему. Он не был включен сюда для краткости статьи.
Надеюсь, эта статья вам помогла! Спасибо или читаю.