Python Social Auth – обов'язковий email при реєстрації через соціальні мережі

4 хв. читання

Проблема

В django проектах для авторизації через соціалки використовую python-social-auth. Виникла ситуація, що не у всіх в профілі у facebook є email. Вірніше, я до цього не відразу дійшов. На пошту сипались листи про 500 помилку при реєстрації через fb: email field can not be null (ну чи щось таке). Я думав, це або бага в коді в мене, або неправильно запитую дані у фб, от він і не повертає пошти. Випадково дізнався, що можлива ситуація, коли email просто не вказаний – от вам і причина.

Рішення

Я ще до цього користувався django-allauth, але він якось не зайшов через те, що ключі та ідентифікатори зберігались в базі, тож при кожному розгорненні проекту треба було заповнювати ці поля. Але! Там така ситуація, коли соціалка не повернула пошти вже була передбачена: просто показувати юзеру форму, щоб він ввів дані і далі продовжувати вже по накатаній схемі. Хоча в PSA все ж зовсім по іншому, але загальна картина була зрозуміла.

Код

В PSA є pipeline!

Виявляється, там можна не тільки тягнути аватар з соціалки, а й цілком реалізувати наш кейс. Далі: код.

pipeline.py

@partial
def require_email(strategy, details, user=None, is_new=False, *args, **kwargs):
   if user and user.email:
      return
   elif is_new and not details.get('email'):
      email = strategy.request_data().get('email')
      if email:
         details['email'] = email
			else:
            current_partial = kwargs.get('current_partial')
            return strategy.redirect(
               '{0}?partial_token={1}'.format(
               reverse('app:require_email'),
               current_partial.token
            ))

Є такий декоратор: partial. Він створює об'єкт з даними та токен до нього, за який в майбутньому можна доступитись. Тобто основний момент: десь зберегти вже поточні дані, перервати виконання pipelines, користувача перекинути на сторінку з формою, де він залишає свій email. Юзер заповнює форму і все відсилаємо назад на ту саму url: /social/facebook (замість social у вас може бути щось інше). А вже python-social-auth сам розпізнає токен і забере потрібні йому дані.

Тож все, що нам тут треба: взяти токен і зробити редірект на сторінку де буде форма з полем для e-mail.

Далі view:

def require_email(request):
    
		strategy = load_strategy()
    partial_token = request.GET.get('partial_token')
    partial = strategy.partial_load(partial_token)
    return render( request, 'require_email.html', { 
       'email_required': True,  'partial_backend_name': partial.backend, 'partial_token': partial_token
        }
    )

За токеном беремо дані, зокрема там є бекенд. Це все передаємо в шаблон:

template.html

<form action="{% url "social:complete" backend=partial_backend_name %}" method="POST">{% csrf_token %}

    <input name="partial_token" type="hidden" value="{{ partial_token }}">
    <input autofocus="" id="email" name="email" type="email" value="">
    <button type="submit">Register</button>
</form>

Ну і все що нам треба: поле для e-mail. В hidden передаємо токен, і це все посилаємо на подальше опрацювання social-auth, саме тут потрібен був бекенд, щоб відіслати за потрібною адресою:

action="{% url "social:complete" backend=partial_backend_name %}"

Ось і все! Профіт!

Робочий django додаток з прикладом є на github https://github.com/dima-kov/psa-email-required

Висновки

Все робиться доволі легко!

Додумався не сам! Дякую великодушним користувачам stackowerflow, виявляється в python-social-auth є репо з прикладами, тільки там трохи заплутано. Тому й вирішив оформити в репозиторій, щоб в майбутньому мати під рукою.

І на codeguida написав, можливо, комусь життя полегшиться)

Keep calm and continue to code hard!

Помітили помилку? Повідомте автору, для цього достатньо виділити текст з помилкою та натиснути Ctrl+Enter
Codeguida 5.8K
Приєднався: 8 місяців тому
Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Вхід / Реєстрація