我正在使用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,则执行如下请求:
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 Framework提供的可浏览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。
使用你的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”作为第三方后端,但是任何后端的过程都是相同的。
从移动应用程序的角度来看,你仅重定向到/authorizeDjango OAuth Toolkit提供的网址。从那里开始,移动应用程序将一直等到到达回调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客户端共享他们的社交信息,而是希望你(尽可能多地)将信息保密,而是向所有人公开这些信息。
验证对你的API的请求 当移动应用程序随后使用你的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 dat
同样,所有这些都由Django OAuth Toolkit处理,并且不需要额外的工作来实现。
使用本机SDK 在大多数情况下,你将通过自己的网站对用户进行身份验证,并使用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对传入的令牌进行假设。但是,在某些情况下,这种风险可能值得承担,因此你应该在进行评估之前把它扔出去。你需要在用户的快速登录和本机登录之间进行权衡,并可能处理不良或恶意令牌。