簡體   English   中英

如何將Django OAuth Toolkit與Python Social Auth結合使用?

[英]How can I use Django OAuth Toolkit with Python Social Auth?

我正在使用Django Rest Framework構建API。 后來,該API應該由iOS和Android設備使用。 我想允許我的用戶使用Facebook和Google等oauth2提供程序進行注冊。 在這種情況下,他們完全不必在我的平台上創建帳戶。 但是,當我沒有django-oauth-toolkit的Facebook / Google帳戶時,用戶也應該能夠注冊,所以我有自己的oauth2-provider。

對於外部提供程序,我使用的是python-social-auth,它可以正常工作並自動創建用戶對象。

我希望客戶端使用承載令牌進行身份驗證,這對於與我的提供程序注冊的用戶來說效果很好(django-oauth-toolkit為Django REST框架提供了身份驗證方案和權限類)。
但是,python-social-auth僅實現基於會話的身份驗證,因此沒有直接的方法可以代表由外部oauth2提供程序注冊的用戶發出經過身份驗證的API請求。

如果我使用django-oauth-toolkit生成的access_token,則執行如下請求:

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

但是,以下操作無效,因為沒有針對Django REST Framework的相應身份驗證方案,並且python-social-auth提供的AUTHENTICATION_BACKENDS僅適用於基於會話的身份驗證:

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

使用python-social-auth進行身份驗證后,使用Django REST框架提供的可瀏覽API可以正常工作,只有沒有會話cookie的API調用才起作用。

我想知道解決此問題的最佳方法是什么。 從我的角度來看,我基本上有兩個選擇:

答:當用戶使用外部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請求身份驗證。 我可以通過編寫自定義后端並使用register_by_access_token使自己的用戶進入python-social-auth。 但是,由於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對每個無狀態API請求執行整個oauth2-flow,而是對照存儲在數據庫中的數據進行檢查,因為該數據庫實際上並未針對查詢進行優化存儲為JSON(盡管我可以使用UserSocialAuth.objects.get(extra_data__contains =))。
我還必須檢查一下訪問令牌的范圍,並使用它們來檢查權限,這是django-oauth-toolkit已經完成的工作( TokenHasScoperequired_scopes等)。

目前,我傾向於使用選項A,因為django-oauth-toolkit提供了與Django Rest Framework的良好集成,並且可以立即獲得所需的一切。 唯一的缺點是我必須將python-social-auth檢索到的access_tokens“注入” django-oauth-toolkit的AccessToken模型,這在某種程度上讓人感到不對,但這可能是迄今為止最簡單的方法。

是否有人對此有異議或以不同的方式解決了相同的問題? 我是否遺漏了一些明顯的東西並使我的生活變得更加艱難? 如果有人已經將django-oauth-toolkit與python-social-auth和外部oauth2提供程序集成在一起,我將非常感謝您提供的一些指示或意見。

實施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”作為第三方后端,但是任何后端的過程都是相同的。

從移動應用程序的角度來看, 您僅重定向到Django OAuth Toolkit提供的/authorize網址 從那里開始,移動應用程序將一直等到到達回調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客戶端) 永遠不會收到Facebook /第三方OAuth令牌 這非常重要,因為它可以確保您的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對傳入的令牌進行假設。但是,在某些情況下, 這種風險可能值得 ,因此您應該在進行評估之前把它扔出去。 您需要在用戶的快速登錄和本機登錄之間進行權衡,並可能處理不良或惡意令牌

我通過使用您的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's 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"

我只是不確定我生成令牌的方式,這是一種好習慣嗎? 好吧,與此同時,它有效!!

也許django-rest-framework-social-oauth2是您想要的。 該軟件包取決於您已經使用的python-social-authdjango-oauth-toolkit 我快速瀏覽了整個文檔,似乎可以實現您要嘗試執行的操作。

我正在用EXPO做React Native,用Django REST框架做Django。 這篇博客文章結束了我通過Facebook https://medium.com/@gabriel_gamil/react-native-expo-django-facebook-authentication-sign-in-83625c49da7解決注冊(注冊)的方式

tldr; 使用django-rest-auth https://django-rest-auth.readthedocs.io/en/latest/index.html

使用Django-allauth https://django-allauth.readthedocs.io/en/latest/

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM