Эта статья продолжает пост, в котором был рассмотрен один из алгоритмов аутентификации пользователя через платформу 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, обсуждаем вопросы с собесов и проводим другие активности.