Подтвердить что ты не робот

Как я могу использовать Django OAuth Toolkit с Python Social Auth?

Я создаю API, используя Django Rest Framework. Позже этот API будет потребляться устройствами iOS и Android. Я хочу разрешить моим пользователям регистрироваться с oauth2-провайдерами, такими как Facebook и Google. В этом случае им не нужно создавать учетную запись на моей платформе вообще. Но пользователи также должны иметь возможность регистрироваться, если у вас нет учетной записи Facebook/Google, для которой я использую django-oauth-toolkit, поэтому у меня есть собственный поставщик oauth2.

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

Я хочу, чтобы клиенты аутентифицировались с помощью токенов-носителей, что отлично подходит для пользователей, которые подписались с моим поставщиком (django-oauth-toolkit предоставляет схему аутентификации и классы разрешений для Django REST Framework).
Однако python-social-auth реализует только аутентификацию на основе сеанса, поэтому нет простого способа сделать аутентифицированные запросы API от имени пользователей, зарегистрированных внешним поставщиком oauth2.

Если я использую access_token, созданный django-oauth-toolkit, выполнение такого запроса работает:

curl -v -H "Authorization: Bearer <token_generated_by_django-oauth-toolkit>" http://localhost:8000/api/

Однако следующее не работает, поскольку нет соответствующей схемы аутентификации для Django REST Framework, а AUTHENTICATION_BACKENDS, предоставленные python-social-auth, работают только для проверки на основе сеанса:

curl -v -H "Authorization: Bearer <token_stored_by_python-social-auth>" http://localhost:8000/api/

Использование API-интерфейса для просмотра, предоставляемого Django REST Framework после аутентификации с помощью python-social-auth, очень просто, только API-вызовы без файла cookie сеанса не работают.

Мне интересно, какой лучший подход для этой проблемы. Как я его вижу, у меня есть в основном два варианта:

A: Когда пользователь подписывается с внешним поставщиком oauth2 (обрабатывается python-social-auth), подключитесь к процессу для создания oauth2_provider.models.AccessToken и продолжайте использовать 'oauth2_provider.ext.rest_framework.OAuth2Authentication', теперь аутентифицируя также пользователей, которые зарегистрированный у внешнего провайдера. Этот подход предлагается здесь: https://groups.google.com/d/msg/django-rest-framework/ACKx1kY7kZM/YPWFA2DP9LwJ

B: Использовать python-social-auth для аутентификации запроса API. Я мог бы завести своих пользователей в python-social-auth, написав собственный бэкэнд и используя register_by_access_token. Однако, поскольку вызовы API не могут использовать сеансы Django, это означало бы, что мне пришлось бы написать схему аутентификации для Django Rest Framework, которая использует данные, хранящиеся в python-social-auth. Некоторые указатели на то, как это сделать, можно найти здесь:
http://psa.matiasaguirre.net/docs/use_cases.html#signup-by-oauth-access-token
http://blog.wizer.fr/2013/11/angularjs-facebook-with-a-django-rest-api/
http://cbdev.blogspot.it/2014/02/facebook-login-with-angularjs-django.html
Однако, как я понимаю, python-social-auth проверяет только токен при регистрации и позже полагается на сеанс Django. Это означало бы, что мне нужно было бы найти способ предотвратить выполнение python-social-auth всего потока oauth2 для каждого запроса API без состояния и скорее проверить данные, хранящиеся в БД, которые на самом деле не оптимизированы для запросов, поскольку это сохраненный как JSON (я мог бы использовать UserSocialAuth.objects.get(extra_data__contains =), хотя).
Я также должен был бы позаботиться о проверке областей доступа к токену и использовать их для проверки разрешений, что уже делает django-oauth-toolkit (TokenHasScope, required_scopes и т.д.).

В настоящий момент я склоняюсь к использованию опции A, поскольку django-oauth-toolkit обеспечивает хорошую интеграцию с Django Rest Framework, и я получаю все, что мне нужно из коробки. Единственным недостатком является то, что я должен "вводить" access_tokens, полученный python-social-auth, в модель Django-oauth-инструментария AccessToken, которая как-то кажется неправильной, но, вероятно, будет самым простым способом.

Есть ли у кого-нибудь какие-либо возражения против этого или, возможно, решить эту проблему по-другому? Упускаю ли я что-то очевидное и делаю свою жизнь труднее, чем необходимо? Если кто-то уже интегрировал django-oauth-toolkit с python-social-auth и внешними поставщиками oauth2, я был бы очень благодарен за некоторые указания или мнения.

4b9b3361

Ответ 1

Многие трудности с внедрением OAuth сводятся к пониманию того, как должен работать поток авторизации. Это в основном потому, что это "отправная точка" для входа в систему, а при работе с сторонним бэкэнд (используя что-то вроде Python Social Auth) вы на самом деле делаете это дважды: один раз для вашего API и один раз для стороннего API.

Авторизация запросов с использованием вашего API и стороннего бэкэнд

Процесс аутентификации, который вам нужен, - это:

Диаграмма последовательности для опции A

Mobile App -> Your API : Authorization redirect
Your API -> Django Login : Displays login page
Django Login -> Facebook : User signs in
Facebook -> Django Login : User authorizes your API
Django Login -> Your API : User signs in
Your API -> Mobile App : User authorizes mobile app

Я использую "Facebook" в качестве стороннего бэкэнд здесь, но процесс для всех бэкэндов одинаковый.

С точки зрения вашего мобильного приложения вы только перенаправляете URL-адрес /authorize, предоставленный Django OAuth Toolkit. Оттуда мобильное приложение ждет, пока не будет достигнут URL-адрес обратного вызова, как в стандартном потоке авторизации OAuth. Почти все остальное (вход в систему Django, социальный вход и т.д.) Обрабатывается либо Django OAuth Toolkit, либо Python Social Auth в фоновом режиме.

Это также будет совместимо с почти любыми библиотеками OAuth, которые вы используете, и поток авторизации будет работать одинаково независимо от того, какой бэкэнд сторонней стороны используется. Он даже будет обрабатывать (общий) случай, когда вам нужно будет поддерживать бэкэн аутентификации Django (адрес электронной почты/имя пользователя и пароль), а также сторонний логин.

Вариант A без стороннего бэкэнд

Mobile App -> Your API : Authorization redirect
Your API -> Django Login : Displays login page
Django Login -> Your API : User signs in
Your API -> Mobile App : User authorizes mobile app

Важно также отметить, что мобильное приложение (которое может быть любым клиентом OAuth) никогда не получает токены OAuth от Facebook/третьих лиц. Это невероятно важно, так как это гарантирует, что ваш API действует как посредник между клиентом OAuth и социальными учетными записями пользователей.

Последовательная диаграмма с вашим API как гейткипер

Mobile App -> Your API : Authorization redirect
Your API -> Mobile App : Receives OAuth token
Mobile App -> Your API : Requests the display name
Your API -> Facebook : Requests the full name
Facebook -> Your API : Sends back the full name
Your API -> Mobile App : Send back a display name

В противном случае клиент OAuth сможет обойти ваш API и делать запросы от вашего имени сторонним API.

Схема последовательности для обхода вашего API

Mobile App -> Your API : Authorization redirect
Your API -> Mobile App : Receives Facebook token
Mobile App -> Facebook : Requests all of the followers
Facebook -> Mobile App : Sends any requested data

Вы заметите, что на данный момент вы потеряли бы контроль над сторонними токенами. Это особенно опасно, потому что большинство токенов могут получить доступ к широкому спектру данных, которые открывают дверь для злоупотреблений и в конечном итоге подпадают под ваше имя. Скорее всего, те, кто вошел в ваш API/веб-сайт, не собирались делиться своей социальной информацией с клиентом OAuth и ожидали, что вы будете хранить эту информацию в личном (насколько это возможно), но вместо этого вы раскрываете эту информацию всем.

Аутентификация запросов к вашему API

Когда мобильное приложение затем использует ваш токен OAuth для запросов на ваш API, вся проверка подлинности происходит через Django OAuth Toolkit (или ваш поставщик OAuth) в фоновом режиме. Все, что вы видите, это то, что с вашим запросом связан User.

Как подтверждены токены OAuth

Mobile App -> Your API : Sends request with OAuth token
Your API -> Django OAuth Toolkit : Verifies the token
Django OAuth Toolkit -> Your API : Returns the user who is authenticated
Your API -> Mobile App : Sends requested data back

Это важно, потому что после стадии авторизации не должно иметь значения, если пользователь приходит из системы проверки подлинности Facebook или Django. Для вашего API просто требуется User для работы, и ваш поставщик OAuth должен иметь возможность обрабатывать аутентификацию и проверку токена.

Это не сильно отличается от того, как среда Django REST аутентифицирует пользователя при использовании аутентификации с поддержкой сеанса.

Схема последовательности для аутентификации с использованием сеансов

Web Browser -> Your API : Sends session cookie
Your API -> Django : Verifies session token
Django -> Your API : Returns session data
Your API -> Django : Verifies the user session
Django -> Your API : Returns the logged in user
Your API -> Web Browser : Returns the requested data

Опять же, все это обрабатывается Django OAuth Toolkit и не требует дополнительной работы для реализации.

Работа с родным SDK

В большинстве случаев вы будете аутентифицировать пользователя через свой собственный сайт и использовать Python Social Auth для обработки всего. Но одним из примечательных исключений является использование собственного SDK, поскольку аутентификация и авторизация обрабатываются через собственную систему, что означает , что вы полностью обходите свой API, Это отлично подходит для приложений, которым необходимо войти в систему с третьей стороной или приложениями, которые вообще не используют ваш API, но это кошмар, когда оба объединяются.

Это связано с тем, что ваш сервер не может подтвердить логин и вынужден предположить, что логин действителен и подлинный, что означает, что он обходит любую безопасность, Python Social Auth дает вам.

Использование собственного SDK может вызвать проблемы

Mobile App -> Facebook SDK : Opens the authorization prompt
Facebook SDK -> Mobile App : Gets the Facebook token
Mobile App -> Your API : Sends the Facebook token for authorization
Your API -> Django Login : Tries to validate the token
Django Login -> Your API : Returns a matching user
Your API -> Mobile App : Sends back an OAuth token for the user

Вы заметите, что это пропускает ваш API на этапе аутентификации, а затем заставляет ваш API делать предположения о переданном токене. Но есть определенные случаи, когда этот риск может стоить того, /strong > , поэтому вы должны оценить это, прежде чем выбросить его. Это компромисс между быстрым и собственным входами для пользователя и , который может обрабатывать вредоносные или вредоносные токены.

Ответ 2

Я решил это, используя ваш вариант A.

То, что я делаю, - это регистрация пользователей, которые используют третью сторону для регистрации по их стороннему токену доступа.

url(r'^register-by-token/(?P<backend>[^/]+)/$',
    views.register_by_access_token),

Таким образом, я могу выполнить запрос GET, подобный этому:

GET http://localhost:8000/register-by-token/facebook/?access_token=123456

И вызывается register_by_access_token. request.backend.do_auth запросит у провайдера информацию пользователя из токена и волшебным образом зарегистрирует учетную запись пользователя с информацией или значком пользователя, если он уже зарегистрирован.

Затем я создаю маркер вручную и возвращаю его как JSON, чтобы клиент мог запросить мой API.

from oauthlib.common import generate_token
...
@psa('social:complete')
def register_by_access_token(request, backend):
    # This view expects an access_token GET parameter, if it needed,
    # request.backend and request.strategy will be loaded with the current
    # backend and strategy.
    third_party_token = request.GET.get('access_token')
    user = request.backend.do_auth(third_party_token)

    if user:
        login(request, user)

        # We get our app!   
        app = Application.objects.get(name="myapp")

        # We delete the old token
        try:
            old = AccessToken.objects.get(user=user, application=app)
        except:
            pass
        else:
            old.delete()

        # We create a new one
        my_token = generate_token()

        # We create the access token 
        # (we could create a refresh token too the same way) 
        AccessToken.objects.create(user=user,
                                   application=app,
                                   expires=now() + timedelta(days=365),
                                   token=my_token)

        return "OK" # you can return your token as JSON here

    else:
        return "ERROR"

Я просто не уверен в том, как я генерирую токен, это хорошая практика? Ну, в то же время, это работает!

Ответ 3

Может быть, django-rest-framework-social-oauth2 - это то, что вы ищете. Этот пакет зависит от python-social-auth и django-oauth-toolkit, которые вы уже используете. Я быстро просмотрел документацию, и она, кажется, реализует то, что вы пытаетесь сделать.

Ответ 4

Я делал React Native с экспозицией, а Django - с каркасом Django REST. Этот блог закончился тем, как я решил регистрацию (регистрацию) в Facebook https://medium.com/@gabriel_gamil/react-native-expo-django-facebook-authentication-sign-in-83625c49da7

TL;DR; используйте django-rest-auth https://django-rest-auth.readthedocs.io/en/latest/index.html

используйте Джанго-Аллаута https://django-allauth.readthedocs.io/en/latest/