python - 如何将 Django OAuth Toolkit 与 Python Social Auth 结合使用?

标签 python django oauth-2.0 django-rest-framework python-social-auth

我正在使用 Django Rest Framework 构建 API。稍后这个 API 应该被 iOS 和 Android 设备使用。我想允许我的用户注册像 Facebook 和谷歌这样的 oauth2 提供商。在这种情况下,他们根本不需要在我的平台上创建帐户。但是用户在没有 Facebook/Google 帐户时也应该能够注册,我使用的是 django-oauth-toolkit,所以我有自己的 oauth2-provider。

对于外部提供者,我使用的是 python-social-auth,它工作正常并自动创建用户对象。

我希望客户端使用不记名 token 进行身份验证,这对于在我的提供商处注册的用户来说效果很好(django-oauth-toolkit 为 Django REST Framework 提供了身份验证方案和权限类)。
但是,python-social-auth 仅实现基于 session 的身份验证,因此没有直接的方法代表由外部 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 仅适用于基于 session 的身份验证:
curl -v -H "Authorization: Bearer <token_stored_by_python-social-auth>" http://localhost:8000/api/

在使用 python-social-auth 进行身份验证后使用 Django REST Framework 提供的可浏览 API 工作得很好,只有没有 session cookie 的 API 调用不起作用。

我想知道解决这个问题的最佳方法是什么。在我看来,我基本上有两种选择:

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请求认证。我可以通过编写自定义后端并使用 register_by_access_token 来让我自己的用户进入 python-social-auth。但是,由于 API 调用无法使用 Django session ,这意味着我必须为 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 只在登录时验证 token ,然后依赖于 Django session 。这意味着我必须找到一种方法来防止 python-social-auth 为每个无状态 API 请求执行整个 oauth2-flow,而是检查存储在数据库中的数据,因为它没有真正针对查询进行优化存储为 JSON(不过我可以使用 UserSocialAuth.objects.get(extra_data__contains=))。

我还必须负责验证访问 token 的范围并使用它们来检查权限,django-oauth-toolkit 已经这样做了( TokenHasScoperequired_scopes 等)。

目前,我倾向于使用选项 A,因为 django-oauth-toolkit 提供了与 Django Rest Framework 的良好集成,我可以立即获得所需的一切。唯一的缺点是我必须将 python-social-auth 检索到的 access_tokens“注入(inject)”到 django-oauth-toolkit 的 AccessToken 模型中,这在某种程度上感觉不对,但可能是迄今为止最简单的方法。

有没有人反对这样做,或者可能以不同的方式解决了同样的问题?我是否遗漏了一些明显的东西并使我的生活变得比必要的更艰难?
如果有人已经将 django-oauth-toolkit 与 python-social-auth 和外部 oauth2 提供程序集成,我将非常感谢您提供一些指示或意见。

最佳答案

实现 OAuth 的很多困难归结为理解授权流程应该如何工作。这主要是因为这是登录的“起点”,并且在使用第三方后端(使用 Python Social Auth 之类的东西)时,您实际上是在执行两次此操作:一次用于您的 API,一次用于第三方应用程序接口(interface)。

使用您的 API 和第三方后端授权请求

您需要经历的身份验证过程是:

Sequence diagram for option 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”作为第三方后端,但任何后端的过程都是相同的。

从您的移动应用程序的角度来看,您只是重定向到 /authorize由 Django OAuth 工具包提供的 url .从那里,移动应用程序一直等到到达回调 url,就像在标准 OAuth 授权流程中一样。几乎所有其他内容(Django 登录、社交登录等)都由 Django OAuth Toolkit 或 Python Social Auth 在后台处理。

这也将与您使用的几乎所有 OAuth 库兼容,并且无论使用什么第三方后端,授权流程都将相同。它甚至可以处理您需要能够支持 Django 的身份验证后端(电子邮件/用户名和密码)以及第三方登录的(常见)情况。

Option A without a third-party backend

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 token .这非常重要,因为它确保您的 API 充当 OAuth 客户端和您用户的社交帐户之间的中介。

Sequence diagram with your API as the gatekeeper

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 发出请求。

Sequence diagram for bypassing your 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

您会注意到此时 您将失去对第三方 token 的所有控制 .这尤其危险,因为大多数 token 可以访问范围广泛的数据,这为滥用打开了大门,并最终以您的名义消失。最有可能的是,那些登录您的 API/网站的人并不打算与 OAuth 客户端共享他们的社交信息,而是希望您(尽可能)将这些信息保密,但是 相反,您将这些信息暴露给所有人 .

验证对您的 API 的请求

当移动应用程序随后使用您的 OAuth token 向您的 API 发出请求时,所有身份验证都在后台通过 Django OAuth Toolkit(或您的 OAuth 提供程序)进行。 所有你看到的是有一个 User与您的请求相关联。

How OAuth tokens are validated

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 提供程序应该能够处理 token 的身份验证和验证。

这与 Django REST framework 在使用 session 支持的身份验证时对用户进行身份验证的方式没有太大区别。

Sequence diagram for authenticating using sessions

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 工具包处理 并且不需要额外的工作来实现。

使用原生 SDK

在大多数情况下,您将通过自己的网站对用户进行身份验证,并使用 Python Social Auth 来处理所有事情。但一个值得注意的异常(exception)是使用原生 SDK 时,如 身份验证和授权通过 native 系统处理 ,这意味着 你完全绕过了你的 API .这对于需要通过第三方登录的应用程序或根本不使用您的 API 的应用程序非常有用,但 当两者走到一起时,这是一场噩梦 .

这是因为 您的服务器无法验证登录 并被迫假设登录有效且真实 ,这意味着它绕过了 Python Social Auth 为您提供的所有安全性。

Using a native SDK can cause issues

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 对传入的 token 做出假设。但肯定存在 的情况。这种风险可能值得 ,所以你应该在扔掉它之前评估它。这是 之间的权衡您的用户的快速本地登录 可能处理不良或恶意 token .

关于python - 如何将 Django OAuth Toolkit 与 Python Social Auth 结合使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27051209/

相关文章:

python - 在 python 中重新创建此图表 - 这是什么类型的图表?

django - 无法在皇帝模式下使用 ini 文件运行 uwsgi - 权限被拒绝

api - 授权 JWT token 中使用 Claims 的边界 OAuth2+OIDC

python - 通过python将数据从MongoDb加载到Elasticsearch

python - 使用 fromkeys 和可变对象创建字典。惊喜

django - 如何在 Django 中支持 AutoField(primary_key=False)?

azure - 用于查询 azure SQL 数据的移动服务 API 或 .net Web API

android - 通过 playstore firebase oauth2 分发时谷歌登录不工作

python - 使用 Pycurl 获取 HTML

python - edX 供应问题 : get stuck at, 任务:[edxapp |将 edx-platform repo check out 到 {{edxapp_code_dir}}]