为啥 Django REST Framework 提供不同的身份验证机制

Posted

技术标签:

【中文标题】为啥 Django REST Framework 提供不同的身份验证机制【英文标题】:Why does Django REST Framework provide different Authentication mechanisms为什么 Django REST Framework 提供不同的身份验证机制 【发布时间】:2014-08-21 08:47:38 【问题描述】:

为什么 Django REST Framework 实现了与内置 Django 机制不同的身份验证机制?

也就是说,可以配置两种设置类:

    settings.AUTHENTICATION_BACKENDS 处理 Django 级别的身份验证,以及 settings.REST_FRAMEWORK['DEFAULT_AUTHENTICATION_CLASSES'] 在 REST 框架级别进行身份验证

我遇到的问题是我有一个中间件层来检查用户是否登录。

当使用通过会话进行身份验证的 Web 客户端时,这可以正常工作。但是,从移动设备或运行测试套件时(即使用 HTTP 标头和令牌进行身份验证),中间件将用户检测为 AnonymousUser,但当我们到达 REST 框架层时,HTTP Authorization 标头是读取,并且用户已登录。

为什么这些都不会发生在中间件之前?此外,为什么 REST Framework 的身份验证方法不依赖 Django 身份验证后端?

【问题讨论】:

好问题@BillyBBone。我遇到了同样的问题。您有没有想过在中间件中验证 DRF 请求的方法? 【参考方案1】:

默认情况下,Django Rest Framework 不会在中间件中执行身份验证,原因与 Django 默认情况下不在中间件中执行身份验证的原因相同:中间件适用于所有视图,当您只想验证对一小部分你的意见。此外,能够为不同的 API 端点提供不同的身份验证方法是一个非常方便的功能。

Rest Framework 的身份验证方法不依赖于 Django 身份验证后端,因为 Django 的后端针对常见情况进行了优化,并且与用户模型密切相关。 Rest Framework 旨在简化:

    使用多种不同的身份验证方法。 (您想要基于 HMAC 的身份验证?完成!这在 django auth 框架中是不可能的) 无需数据库即可提供 API 数据。 (你有一个所有数据都在内存中的 redis 数据库?在几毫秒内提供它,而无需等待到 DB 用户模型的往返。)

【讨论】:

您知道为 DRF 请求创建中间件的方法吗? @SteveWalsh 与任何请求的中间件相同。如果您需要它专门在 DRF 视图上运行,您可以测试当前视图是否是 DRF 的基础 ApiView 的子类。 @awidgery ApiView in __self__.__class__.__mro__ 我想。 有人对这个问题有实际答案吗?两者有什么区别? @psilocybin process_request 中间件在 url 路由之前运行,并且只考虑请求标头。 process_view 中间件在 url 路由完成后运行,可以考虑这个请求将被路由到的视图。因此无法在process_request 中间件中对此进行测试。您可以做的最好的事情是测试请求的 url 路径是否以您知道 API 端点所在的某个前缀开头。【参考方案2】:

Thomas 的回答很好地解释了原因。我的回答更多地涉及您可以做些什么。我还有一个确定当前用户的中间件类。我需要这个,因为我们有一些自动进程(cron),我想将它们归因于超级用户,并且我有一些模型函数无法访问请求对象但需要知道当前用户是谁职能。因此,正如您在我们通过 REST 框架添加 API 时注意到的那样,这产生了一些问题。这是我的解决方案(您的解决方案需要根据您的用例进行调整):

from threading import local

_user = local()     # thread-safe storage for current user used by middleware below

class CurrentUserMiddleware(object):
    """ Defines Middleware for storing the currently active user """

    def process_request(self, request):
        if not request:
            # Clear the current user if also clearing the request.
            _user.value = 1  # One represents automatic actions done by super admin

        else:
            _user.value = request.user

            if not _user.value or not _user.value.is_authenticated:
                try:
                    authenticator = TokenAuthentication()
                    auth = authenticator.authenticate(request)

                    if auth:
                        _user.value = auth[0]
                except Exception as e:
                    pass

    def process_response(self, request, response):
        _user.value = None

        return response

身份验证器位处理查看请求是否已通过 REST 框架的身份验证并获取用户。

【讨论】:

以上是关于为啥 Django REST Framework 提供不同的身份验证机制的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Django REST Framework 提供不同的身份验证机制

为啥 Django Rest Framework 不鼓励模型级别验证?

为啥我的 Django REST Framework 视图集 URL 没有解析?

Django Rest Framework - 为啥在尝试使用不正确的凭据登录用户时返回 200 状态码?

为啥从 django rest 框架返回的 JSON 在响应中有正斜杠?

Django-rest-framework 和 django-rest-framework-jwt APIViews and validation Authorization headers