如果我想确保一个视图被列为具有公共访问权限,是否有一个与@public_access等效的装饰器,它与@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.middleware import publi @public def some_view(request): #... # Login required is added automatically def some_private_view(request): #...
此外,您可能希望查看"自动装饰django项目的所有视图"博客文章
如前面提到的海报,默认情况下不需要登录.
但是,有时阻止登录用户的某些视图很有用 - 例如,登录用户无法使用网站的注册页面.在这种情况下,您可以根据现有的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