如果我想确保一个视图被列为具有公共访问权限,是否有一个与@public_access等效的装饰器,它与@login_required相反,并明确表示该视图应该是公共可访问的?
我想到的一个用例是自动将“@csrf_exempt”添加到所有公共视图中,此外还要在代码中明确说明该视图应该是公共可访问的。
答案 0 :(得分:11)
不幸的是,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"博文
答案 1 :(得分:5)
正如之前提到的海报,默认情况下不需要登录。
但是,有时阻止登录用户的某些视图很有用 - 例如,登录用户无法使用网站的注册页面。在这种情况下,您可以根据现有的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
答案 2 :(得分:1)
有点晚了,但解决这个问题的另一个简单方法是依赖另一个装饰器并添加一个lambda函数:
from django.contrib.auth.decorators import user_passes_test
@user_passes_test(lambda u: u.is_anonymous)
答案 3 :(得分:1)
@permission_classes([permissions.AllowAny])
答案 4 :(得分:0)
“不需要登录”是默认设置。如果你想注释一个视图永远不应该被登录限制,那么你应该在docstring中这样做。
答案 5 :(得分:0)
我使用django-decorator-include使用login_required
装饰器来保护整个应用,而不是一次保护一个视图。我的应用程序的主要urls.py如下所示:
path('my_secret_app/', decorator_include(login_required, ('my_secret_app.urls', 'my_secret_app'))),
这很好用,除非我的一个应用程序具有一个需要公开的视图。
为解决这个问题,我编写了自己的login_required
和login_not_required
。我的login_required
是基于django的django.contrib.auth.decorators.login_required
进行的,但是经过了稍微修改,可以真正在意将视图标记为不需要登录时的情况。
我的项目称为mysite
。
我的应用名为my_secret_app
。
我在my_secret_app
中的公开视野称为MyPublicView
。
我的整个解决方案如下:
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 / urls.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):
...
无论您是子类View
,ListView
,CreateView
,UpdateView
,TemplateView
还是其他子类,您都应该能够做同样的事情其他任何一个。如果您使用函数作为视图,它也应该起作用,尽管我没有尝试过:
@login_not_required
def MyPublicView(request):
...
答案 6 :(得分:0)
您可以使用 user_passes_test 并添加一个要求,anonymous_required。这与 login_required 的工作方式相反,您可以在注册和登录页面上使用 - 用户在登录后仍然看到登录页面有点烦人。 你会这样做:
from django.contrib.auth.decorators import user_passes_test
#Anonymous required
def anonymous_required(function=None, redirect_url=None):
if not redirect_url:
redirect_url = settings.LOGIN_REDIRECT_URL
actual_decorator = user_passes_test(
lambda u: u.is_anonymous,
login_url=redirect_url
)
if function:
return actual_decorator(function)
return actual_decorator
#Application of the Decorator
@anonymous_required
def register(request):
#Your code goes here