Django视图所需的@login_decorator的反面是什么?
如果我想确保某个视图被列为具有公共访问权限,是否有一个与@public\u access相当的装饰器,它将与@login\u required相反,并明确指出该视图应始终可公开访问Django视图所需的@login_decorator的反面是什么?,django,django-authentication,Django,Django Authentication,如果我想确保某个视图被列为具有公共访问权限,是否有一个与@public\u access相当的装饰器,它将与@login\u required相反,并明确指出该视图应始终可公开访问 我想到的一个用例是自动将“@csrf_emption”添加到所有公共视图中,并在代码中明确该视图应可公开访问。默认为“不需要登录”。如果您想注释视图不应被登录限制,那么您应该在docstring中这样做。不幸的是,Django中目前没有对此的内置支持,当意外忘记@login\u required时,您可能会暴露敏感信
我想到的一个用例是自动将“@csrf_emption”添加到所有公共视图中,并在代码中明确该视图应可公开访问。默认为“不需要登录”。如果您想注释视图不应被登录限制,那么您应该在docstring中这样做。不幸的是,Django中目前没有对此的内置支持,当意外忘记
@login\u required
时,您可能会暴露敏感信息
以下是我的一个项目的解决方案:
中间件/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)))
MIDDLEWARE_CLASSES = (
#...
'middleware.security.NonpublicProfilefullMiddleware',
#...
)
settings.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)))
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):
#...
from.middleware导入publi
@公开的
定义某些视图(请求):
#...
#自动添加所需的登录名
定义一些私有视图(请求):
#...
此外,您可能希望查看博客帖子,正如前面提到的海报一样,默认情况下不需要登录 然而,有时阻止登录用户查看某些视图是有用的——例如,登录用户能够使用站点的注册页面是没有意义的。在这种情况下,您可以根据现有的登录所需的decorator执行类似的操作
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
有点晚了,但解决此问题的另一个简单方法是依赖另一个装饰器并添加lambda函数:
from django.contrib.auth.decorators import user_passes_test
@user_passes_test(lambda u: u.is_anonymous)
@权限类([permissions.AllowAny])我使用所需的login\u
decorator来保护整个应用程序,而不是一次一个视图。我的应用程序的主URL.py如下所示:
path('my_secret_app/', decorator_include(login_required, ('my_secret_app.urls', 'my_secret_app'))),
这非常有效,除非我的一个应用程序有一个视图需要公开
为了解决这个问题,我编写了自己的login\u required
和login\u not\u required
。我的login\u required
基于django的django.contrib.auth.decorators.login\u required
,但稍微修改了一下,以便在视图被标记为不需要登录时真正注意
我的项目名为mysite
我的应用程序名为My\u secret\u app
myu secret\u应用程序中的我的公共视图被称为MyPublicView
我的整个解决方案如下所示:
path('my_secret_app/', decorator_include(login_required, ('my_secret_app.urls', 'my_secret_app'))),
mysite/lib.py
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.contrib.auth.decorators import user_passes_test
# A copy of django.contrib.auth.decorators.login_required that looks for login_not_required attr
def login_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url=None):
actual_decorator = user_passes_test(
lambda u: u.is_authenticated,
login_url=login_url,
redirect_field_name=redirect_field_name
)
if function:
login_req = getattr(function, "login_required", True)
if login_req:
return actual_decorator(function)
else:
return function
else:
return actual_decorator
# Decorator to mark a view as not requiring login to access
def login_not_required(f):
f.login_required = False
return f
mysite/url.py
from .lib import login_required
path('my_secret_app/', decorator_include(login_required, ('my_secret_app.urls', 'my_secret_app'))),
my_secret_app/views.py:
from django.utils.decorators import method_decorator
from mysite.lib import login_not_required
class MyPublicView(View):
@method_decorator(login_not_required)
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)
def get(self, request):
...
def post(self, request, *args, **kwargs):
...
无论您是子类化视图
,列表视图
,创建视图
,更新视图
,模板视图
,还是任何其他视图,您都应该能够做同样的事情。如果您使用函数作为视图,它也应该可以工作,尽管我没有尝试过:
@login_not_required
def MyPublicView(request):
...
我认为在某些情况下,如果用户登录,限制对某些功能的访问也是有用的。例如,不允许登录用户填写注册表。。。在这种情况下,您可以使用is_authenticated和is_anonymous的组合:使用“u.is_anonymous()”而不是“not u.is_authenticated()”。查看了解更多信息。见鬼:“编辑必须至少6个字符;这篇文章还有什么需要改进的吗?”该死的没有!u.is_anonymous
中只缺少括号,因此示例不正确。示例正确且有效。你想在哪里加括号?哦,我查过文件了。你是对的,这是正确的,因为django 1.10+是匿名的。但对于Django的早期版本,它将始终为您提供True
,因为是匿名的
was方法。没有任何解释-只有代码。我深入研究了如何导入permission_类,它似乎是rest_框架的一部分,我没有使用它。要么我错了,说几句关于从何处导入它以及在何处添加此代码的话会有所帮助,要么我是对的,这只在有人使用rest框架的情况下才相关,而在最初的问题中没有提到这一点