Эта статья продолжает пост, в котором был рассмотрен один из алгоритмов аутентификации пользователя через платформу Google. Сейчас мы дополним ее механизмом заполнения профиля пользователя данными из Google-аккаунта. Хотелось бы подчеркнуть, что в обеих статьях рассматривается только один из алгоритмов. Он, на мой взгляд, наиболее понятен для начинающих разработчиков, хотя существуют и другие способы. О них можно узнать из документации Django.
Проведя аутентификацию через Google, мы получили только стандартные данные - идентификатор и имя пользователя. Но можно получить и другие, в частности, email, возраст, информацию о себе и т.д.
Реализуем в проекте собственный сервис (pipeline) и добавим в пакет приложения authapp соответствующий модуль (pipeline.py):

Код модуля pipeline.py:
from datetime import datetime from urllib.parse import urlencode from urllib.parse import urlunparse from django.utils import timezone from social_core.exceptions import AuthForbidden import requests from .models import TravelUser, TravelUserProfile def save_user_profile(backend, user, response, *args, **kwargs): if not isinstance(user, TravelUser): return if backend.name != 'google-oauth2': return api_url = urlunparse(( 'https', 'people.googleapis.com', '/v1/people/me', None, urlencode({ 'personFields': 'genders,birthdays,biographies', 'access_token': response['access_token'] }), None )) resp = requests.get(api_url) if resp.status_code != 200: print(f"Ошибка при получении данных от Google API: {resp.status_code} - {resp.text}") return data = resp.json() try: user_profile = user.traveluserprofile except TravelUserProfile.DoesNotExist: user_profile = TravelUserProfile.objects.create(user=user) if 'genders' in data and data['genders']: gender_data = data['genders'][0] if 'value' in gender_data: if gender_data['value'].lower() == 'male': user_profile.gender = TravelUserProfile.MALE elif gender_data['value'].lower() == 'female': user_profile.gender = TravelUserProfile.FEMALE if 'biographies' in data and data['biographies']: about_me_data = data['biographies'][0] if 'value' in about_me_data: user_profile.aboutMe = about_me_data['value'][:512] if 'birthdays' in data and data['birthdays']: birthday_data = data['birthdays'][0] if 'date' in birthday_data: bdate_dict = birthday_data['date'] try: year = bdate_dict.get('year') if year: current_year = timezone.now().date().year age = current_year - year if age < 18: user.delete() raise AuthForbidden('social_core.backends.google.GoogleOAuth2') user.age = age except ValueError as e: print(f"Ошибка парсинга даты рождения: {e}") pass user_profile.save() user.save()
Разберем некоторые важные моменты.
Первым делом мы проверяем, что для аутентификации применяется бэкенд 'google-oauth2':
if backend.name != 'google-oauth2': return
Теперь нам нужно сформировать API-URL, через который мы выполним извлечение необходимых параметров из нашего аккаунта:
api_url = urlunparse(( 'https', 'people.googleapis.com', '/v1/people/me', None, urlencode({ 'personFields': 'genders,birthdays,biographies', 'access_token': response['access_token'] }), None ))
Выполним запрос к этому URL, заодно проверим, что код ответа 200 (все OK):
resp = requests.get(api_url) if resp.status_code != 200: print(f"Ошибка при получении данных от Google API: {resp.status_code} - {resp.text}") return
Получим ответ, из которого извлечем нужный нам словарь с параметрами:
data = resp.json()
Выполним парсинг необходимых параметров – пола, данных о себе и дате рождения (с вычислением возраста). Разумеется, эти данные должны быть заполнены в вашем Google-профиле:
if 'genders' in data and data['genders']: gender_data = data['genders'][0] if 'value' in gender_data: if gender_data['value'].lower() == 'male': user_profile.gender = TravelUserProfile.MALE elif gender_data['value'].lower() == 'female': user_profile.gender = TravelUserProfile.FEMALE if 'biographies' in data and data['biographies']: about_me_data = data['biographies'][0] if 'value' in about_me_data: user_profile.aboutMe = about_me_data['value'][:512] if 'birthdays' in data and data['birthdays']: birthday_data = data['birthdays'][0] if 'date' in birthday_data: bdate_dict = birthday_data['date'] try: year = bdate_dict.get('year') if year: current_year = timezone.now().date().year age = current_year - year if age < 18: user.delete() raise AuthForbidden('social_core.backends.google.GoogleOAuth2') user.age = age except ValueError as e: print(f"Ошибка парсинга даты рождения: {e}") pass
И сохраним данные в профиле:
user_profile.save() user.save()
Для нашего нового сервиса необходимо прописать настройки в модуле settings.py:
SOCIAL_AUTH_PIPELINE = ( 'social_core.pipeline.social_auth.social_details', 'social_core.pipeline.social_auth.social_uid', 'social_core.pipeline.social_auth.auth_allowed', 'social_core.pipeline.social_auth.social_user', 'social_core.pipeline.user.create_user', 'authapp.pipeline.save_user_profile', 'social_core.pipeline.social_auth.associate_user', 'social_core.pipeline.social_auth.load_extra_data', 'social_core.pipeline.user.user_details', )
Если после этого вы запустите проект и сделаете аутентификацию через Google, то увидите ошибку:
"message": "People API has not been used in project 847071034656 before or it is disabled. Enable it by visiting
https://console.developers.google.com/apis/api/people.googleapis.com/overview?project=847071034656
then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.",
Нужно перейти по указанной ссылке и нажать кнопку Enable для установления разрешения на обмен информацией.
После этого можно запустить проект и проверить, что профиль действительно заполняется.
P.S. Я создал небольшой Django-проект, на котором вы можете проверить работоспособность механизма. Скачать его можно здесь. Также приглашаю вас в мой ТГ-канал, где я размещаю авторские материалы по Python, обсуждаем вопросы с собесов и проводим другие активности.
