Python/Django - HTTP认证
我想在我的代码中加入基本的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访问的标准认证共享凭证
2 个回答
1
我会使用Django的类视图中的一个混合类来实现这个功能。
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):
.
.
.
2
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
使用的是同一个用户模型,所以它们并不是分开的。幸运的是,中间件和 后端 都相对简单。网页服务器会拒绝任何凭证无效的请求,所以每当 '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
...