【问题标题】:Python/Django - HTTP authenticationPython/Django - HTTP 身份验证
【发布时间】:2014-07-18 17:53:25
【问题描述】:

如果满足某个条件,我想在我的代码中的某处放置基本的 HTTP 身份验证。条件是请求参数。为简化起见,假设我希望它在 Django 视图中。

我知道如何在 PHP 中做到这一点。这正是我想要的代码块:

if (isset($_REQUEST['key']) && $_REQUEST['key'] === 'value') {
    if (!isset($_SERVER['PHP_AUTH_USER'])) {
        header('WWW-Authenticate: Basic realm="My Realm"');
        header('HTTP/1.0 401 Unauthorized');
        echo 'Text to send if user hits Cancel button';
        exit;
    } else {
        echo "<p>Hello {$_SERVER['PHP_AUTH_USER']}.</p>";
        echo "<p>You entered {$_SERVER['PHP_AUTH_PW']} as your password.</p>";
    }
}

我可以将这段代码放在我的 PHP 脚本中的任何位置,当执行到这些行时,将请求身份验证。如果身份验证失败,脚本执行将停止,并且将与指定的消息一起发送 401 Unauthorized 标头。这就是我在 Python/Django 中想要的。这是一段代码,帮我填一下:

def some_view(request):
    if request.REQUEST.get('key') == 'value':
        # FILL ME IN

我想要什么:

  • 能够将此块放入代码中的任何位置并要求用户进行身份验证(假设我可以使用请求变量,一个 django.http.response.HttpResponse 实例也可以作为响应)
  • 能够指定请求身份验证的条件(例如请求中是否存在参数)
  • 在用户提供无效凭据时停止进一步执行并返回 401 Unauthorized 响应
  • 使解决方案具有可移植性(将代码块复制/粘贴到别处,一旦执行到该处就会触发身份验证)

我不想要的:

  • 在函数调用时硬编码身份验证要求(使用装饰器)
  • 更改我的 Web 应用程序的任何全局设置
  • 更改我希望触发身份验证的代码部分之外的任何其他内容
  • 需要安装任何其他软件包才能使其正常工作
  • 将此身份验证的凭据与已在应用程序中设置的 CMS 访问标准身份验证共享

【问题讨论】:

    标签: python django python-2.7 http-authentication


    【解决方案1】:
    from django.http import HttpResponse
    
    def some_view(request):
        if request.REQUEST.get('key') == 'value':
            if not request.user.is_authenticated():
                response = HttpResponse('Text to send if user hits Cancel button', status=401)
                response['WWW-Authenticate'] = 'Basic realm="My Realm'
                return response
            ...
    

    这将返回401 状态代码,但需要您提供自己的内容/模板。如果您可以接受返回 403 状态码,您可以使用内置的 PermissionDenied 异常,该异常会根据您的“403.html”模板返回 403 页面:

    from django.core.exceptions import PermissionDenied
    
    def some_view(request):
        if request.REQUEST.get('key') == 'value':
            if not request.user.is_authenticated():
                raise PermissionDenied
            ...
    

    编辑:

    要实现 HTTP 基本身份验证,您必须设置您的网络服务器(Apache、nginx,无论您使用什么)来处理这个问题。您应该查看您的网络服务器的文档以了解如何执行此操作。

    Django 实现了RemoteUserBackend 以允许用户使用基本身份验证登录,但这使用与普通ModelBackend 相同的用户模型,因此它们不是分开的。幸运的是,the middlewarethe backend 非常简单。网络服务器将拒绝任何具有无效凭据的请求,因此只要设置了 'REMOTE_USER' 标头(或您使用的任何标头值),用户就会得到正确的身份验证。此标头将在request.META 中可用,因此要检查用户是否使用基本身份验证进行身份验证,您可以使用以下代码:

    from django.http import HttpResponse
    
    def some_view(request):
        if request.REQUEST.get('key') == 'value':
            if request.META.get('REMOTE_USER', None):
                do_something()
            else:
                response = HttpResponse('Text to send if user hits Cancel button', status=401)
                response['WWW-Authenticate'] = 'Basic realm="My Realm'
                return response
            ...
    

    【讨论】:

    • 这似乎在正确的轨道上,但在我的情况下有一个问题,request.user 是登录 Django CMS 的用户,我不希望这样。我希望此身份验证与 Django 中使用的身份验证完全分开。如果您登录了一个,那与另一个无关。基本上我想查看提供的用户名和密码并自行检查。这有可能吗?
    • @morgoth84 更新了我的答案。
    • 谢谢,通过使用您的输入(以及获取身份验证 UN/PW 的此链接:djangosnippets.org/snippets/1304),我设法做我想做的一切,有可能在代码中的任何地方请求身份验证并拥有它与现有应用程序中已使用的其他身份验证方法分开。当我得到 UN/PW 时,我只是在会话中保存了身份验证信息。我将所有内容集成到现有代码中,一切正常,这是一个优雅的解决方案。
    【解决方案2】:

    我会为此使用带有 django 的基于类的视图的 mixin

    class AuthenticationMixin(object):
        def dispatch(self, request, *args, **kwargs):
            if not request.user.is_authenticated:
                return HttpResponse('text, test, text', status=401)
            return super(AuthenticationMixin, self).dispatch(request, *args, **kwargs)
    

    然后您将在视图中使用它,如下所示

    class MyView(AuthenticationMixin, DetailView):
    .
    .
    .
    

    如果有一种观点认为您不想使用身份验证,您需要做的就是不在类声明中对身份验证混合进行子类化

    class MyUnauthenticatedView(DetailView):
    .
    .
    .
    

    【讨论】:

    • 我不知道你为什么认为这会起作用,但是在 __init__ 方法中设置一个局部变量不会有任何作用。
    • 那是因为我忘记添加return语句了。我还意识到 init 方法不是执行此操作的正确位置,因此我已更正。
    • 感谢您的意见。我已经在使用基于类的视图,只是不知道如何在响应中发送身份验证请求以及如何读取提供的凭据以便对它们进行身份验证。最后我设法做到了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-09
    相关资源
    最近更新 更多