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

Комментарии (0)