如果我想确保一个视图被列为具有公共访问权限,那么是否存在一个与@public_access等效的装饰器,它将与@login_required相反,并明确该视图应始终可公开访问?用于Django视图的@login_required装饰器的反义词是什么?
我想到的一个用例是除了在代码中明确指出视图应公开访问之外,还会自动为所有公共视图添加“@csrf_exempt”。
如果我想确保一个视图被列为具有公共访问权限,那么是否存在一个与@public_access等效的装饰器,它将与@login_required相反,并明确该视图应始终可公开访问?用于Django视图的@login_required装饰器的反义词是什么?
我想到的一个用例是除了在代码中明确指出视图应公开访问之外,还会自动为所有公共视图添加“@csrf_exempt”。
不幸的是,目前在Django中没有内置的支持,当你不小心遗忘了@login_required
时,你将面临暴露敏感信息的风险。
下面是我的一个项目的解决方案:
middleware/security.py
:
def public(function):
"""Decorator for public views that do not require authentication
"""
orig_func = function
while isinstance(orig_func, partial): # if partial - use original function for authorization
orig_func = orig_func.func
orig_func.is_public_view = True
return function
def is_public(function):
try: # cache is found
return function.is_public_view
except AttributeError: # cache is not found
result = function.__module__.startswith('django.') and not function.__module__.startswith('django.views.generic') # Avoid modifying admin and other built-in views
try: # try to recreate cache
function.is_public_view = result
except AttributeError:
pass
return result
class NonpublicMiddleware(object):
def process_view_check_logged(self, request, view_func, view_args, view_kwargs):
return
def process_view(self, request, view_func, view_args, view_kwargs):
while isinstance(view_func, partial): # if partial - use original function for authorization
view_func = view_func.func
request.public = is_public(view_func)
if not is_public(view_func):
if request.user.is_authenticated(): # only extended checks are needed
return self.process_view_check_logged(request, view_func, view_args, view_kwargs)
return self.redirect_to_login(request.get_full_path()) # => login page
def redirect_to_login(self, original_target, login_url=settings.LOGIN_URL):
return HttpResponseRedirect("%s?%s=%s" % (login_url, REDIRECT_FIELD_NAME, urlquote(original_target)))
settings.py
:
MIDDLEWARE_CLASSES = (
#...
'middleware.security.NonpublicProfilefullMiddleware',
#...
)
,最后,视图代码:
from <projname>.middleware import publi
@public
def some_view(request):
#...
# Login required is added automatically
def some_private_view(request):
#...
另外,你可能想看"Automatically decorating all views of a django project"博客文章
“不需要登录”是默认设置。如果你想注释一个视图不应该被登录限制,那么你应该在文档字符串中这样做。
作为前面提到的一个海报,不需要登录是默认的。
但是,有时从登录用户中阻止某些视图很有用 - 例如,登录的用户无法使用该站点的注册页面。在这种情况下,你可以做这样的事情,以推翻现存login_required装饰
from django.contrib.auth.decorators import user_passes_test
from django.conf import settings
LOGGED_IN_HOME = settings.LOGGED_IN_HOME
def login_forbidden(function=None, redirect_field_name=None, redirect_to=LOGGED_IN_HOME):
"""
Decorator for views that checks that the user is NOT logged in, redirecting
to the homepage if necessary.
"""
actual_decorator = user_passes_test(
lambda u: not u.is_authenticated(),
login_url=redirect_to,
redirect_field_name=redirect_field_name
)
if function:
return actual_decorator(function)
return actual_decorator
使用“u.is_anonymous()”insted of“not u.is_authenticated()” 。有关更多信息,请参见https://docs.djangoproject.com/en/dev/ref/contrib/auth/#django.contrib.auth.models.AnonymousUser。 – Krozark 2013-10-31 11:33:54
有点晚了,但另一种简单的方法来解决这一问题将依靠另一装饰和添加lambda函数:
from django.contrib.auth.decorators import user_passes_test
@user_passes_test(lambda u: u.is_anonymous)
到底是什么:“编辑必须至少有6个字符;在这篇文章中还有其他改进之处吗?”一定不行! 'u.is_anonymous'中只有缺失的括号,因此示例不正确。 – simplylizz 2017-08-13 18:36:53
该示例正确并有效。你想把另外的括号放在哪里? – 2017-08-15 06:26:14
哦,我检查了文档。你是对的,这是正确的,因为django 1.10+'is_anonymous'成为一个属性。但是对于以前的Django版本,它会给你总是'True',因为'is_anonymous'是方法。 – simplylizz 2017-08-16 07:56:43
@permission_classes([permissions.AllowAny])
我认为这也是在某些情况下有用的* *限制访问某些功能,如果一个用户登录,例如,不允许登录用户完成注册表单...在这种情况下,您可以使用组合is_authenticated和is_anonymous:https://docs.djangoproject.com/en/dev/topics/auth/#authorization-for-anonymous-users – g33kz0r 2011-06-21 11:31:22