[英]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已經完成的工作( TokenHasScope
, required_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。
您需要通過的身份驗證過程是:
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的身份驗證后端(電子郵件/用戶名和密碼)以及第三方登錄的(常見)情況。
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客戶端和用戶的社交帳戶之間的中介。
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發出請求。
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客戶端共享他們的社交信息,而是希望您(盡可能多地)將該信息保密,而是向所有人公開這些信息 。
當移動應用程序隨后使用您的OAuth令牌向您的API發出請求時,所有身份驗證都會在后台通過Django OAuth Toolkit(或您的OAuth提供程序)進行。 您所看到的只是有一個與您的請求關聯的User
。
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處理,並且不需要額外的工作來實現。
在大多數情況下,您將通過自己的網站對用戶進行身份驗證,並使用Python Social Auth處理所有內容。 但是一個值得注意的例外是使用本機SDK時,因為身份驗證和授權是通過本機系統處理的 ,這意味着您將完全繞過API 。 這對於需要與第三方登錄的應用程序或根本不使用您的API的應用程序來說非常有用,但是當兩者結合在一起時 , 這就是一場噩夢 。
這是因為您的服務器無法驗證登錄名 ,並且被迫假定該登錄名是真實和真實的 ,這意味着它繞過了Python Social Auth為您提供的所有安全性。
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-auth
和django-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.