Повторная реализация социальных логинов (в Django) - PullRequest
0 голосов
/ 04 ноября 2018

TL; DR: Можно ли не хранить (Google / Facebook) токены доступа OAuth2, а запрашивать новые при каждом входе в систему?

Я объясню:

Чтобы добавить социальные логины («Войти через Google / Facebook») в приложение Django, у вас есть Python Social Auth . Проблема с этим, по крайней мере для меня, состоит в том, что это намного сложнее, чем хотелось бы, требует много конфигураций, создает дополнительные таблицы в базе данных, и в целом ощущается как много движущихся частей, которые я не понимаю для довольно простой задачи.

Итак, я прочитал немного о Google и Facebook потоках, и они достаточно просты:

  • Сервер имеет ID и секрет .
  • Клиенты / пользователи имеют свои стандартные учетные данные для входа.

Тогда:

  1. Сервер перенаправляет пользователя в Google / Facebook и предоставляет его ID и URI перенаправления .
  2. После того, как пользователь вошел в систему, Google / Facebook перенаправляет их на этот URI с кодом .
  3. Сервер отправляет свой ID , секрет и полученный код в Google / Facebook и получает токен доступа в exchange, который он теперь может использовать для вызовов API от имени пользователя.
  4. Даже самых простых разрешений достаточно, чтобы запросить у Google / Facebook электронную почту пользователя, которую затем можно сопоставить со стандартной моделью пользователя Django (и, если она не существует, пользователь может создать пароль без пароля).

Токен доступа теперь может быть удален, поскольку необходимо было только преобразовать логин Google / Facebook в реальный адрес электронной почты (подтвержденный ими), который используется как идентификатор пользователя only - не более путаница из-за разных аккаунтов при входе через разные социальные сервисы; без дополнительных таблиц; без лишних сложностей.

Вот код, просто чтобы показать, как мало нужно:

# views.py

def login_view(request):
    return render(request, 'login.html', {
        'google_url': 'https://accounts.google.com/o/oauth2/v2/auth?' + urllib.parse.urlencode({
            'client_id': GOOGLE_ID,
            'redirect_uri': request.build_absolute_uri(reverse('oauth_google')),
            'scope': 'profile email',
            'response_type': 'code',
        }),
    }) # use this url in the template as a social login

def oauth_google(request):
    code = request.GET['code']
    response = requests.post('https://www.googleapis.com/oauth2/v4/token', {
        'code': code,
        'client_id': GOOGLE_ID,
        'client_secret': GOOGLE_SECRET,
        'redirect_uri': request.build_absolute_uri(reverse('oauth_google')),
        'grant_type': 'authorization_code',
    }).json()
    id_token = response['id_token']
    response = requests.get('https://www.googleapis.com/oauth2/v3/tokeninfo', {
        'id_token': id_token,
    }).json()
    email = response['email']
    user = User.objects.filter(username=email).first()
    if not user:
        user = User(username=email)
        user.save()
    auth.login(request, user)
    return redirect('index')

# urls.py

urlpatterns = [
    ...
    path('oauth/google', views.oauth_google, name='oauth_google'),
]

Мой вопрос: что мне не хватает? Если это действительно так просто, то почему я не могу найти ответы на StackOverflow / руководства в Интернете, описывающие только это?

Единственная причина, по которой я могу придумать, заключается в том, что токены доступа приходят со сроком действия (от 1 часа до 60 дней); поэтому, возможно, я должен продолжать использовать один и тот же токен до тех пор, пока он действителен (что потребует его хранения и объяснит, почему Python Social Auth нужны дополнительные таблицы). Будет ли Google / Facebook злиться на меня за то, что я слишком часто запрашиваю новые токены доступа, и блокирует меня? Я не смог найти упоминаний об этом в их документации.

EDIT

Вот код Facebook, если кто-то найдет эти фрагменты полезными:

# views.py

def login_view(request):
    return render(request, 'login.html', {
        'facebook_url': 'https://www.facebook.com/v3.2/dialog/oauth?' + urllib.parse.urlencode({
            'client_id': FACEBOOK_ID,
            'redirect_uri': request.build_absolute_uri(reverse('oauth_facebook')),
            'scope': 'email',
        }),
    }) # use this url in the template as a social login

def oauth_facebook(request):
    code = request.GET['code']
    response = requests.get('https://graph.facebook.com/v3.2/oauth/access_token', {
        'code': code,
        'client_id': FACEBOOK_ID,
        'client_secret': FACEBOOK_SECRET,
        'redirect_uri': request.build_absolute_uri(reverse('oauth_facebook')),
    }).json()
    access_token = response['access_token']
    response = requests.get('https://graph.facebook.com/me', {
        'access_token': access_token,
        'fields': 'email',
    }).json()
    email = response['email']
    user = User.objects.filter(username=email).first()
    if not user:
        user = User(username=email)
        user.save()
    auth.login(request, user)
    return redirect('index')

# urls.py

urlpatterns = [
    ...
    path('oauth/facebook', views.oauth_facebook, name='oauth_facebook'),
]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...