2010-02-12 92 views
11

如果我想确保一个视图被列为具有公共访问权限,那么是否存在一个与@public_access等效的装饰器,它将与@login_required相反,并明确该视图应始终可公开访问?用于Django视图的@login_required装饰器的反义词是什么?

我想到的一个用例是除了在代码中明确指出视图应公开访问之外,还会自动为所有公共视图添加“@csrf_exempt”。

回答

10

不幸的是,目前在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"博客文章

+0

我认为这也是在某些情况下有用的* *限制访问某些功能,如果一个用户登录,例如,不允许登录用户完成注册表单...在这种情况下,您可以使用组合is_authenticated和is_anonymous:https://docs.djangoproject.com/en/dev/topics/auth/#authorization-for-anonymous-users – g33kz0r 2011-06-21 11:31:22

0

“不需要登录”是默认设置。如果你想注释一个视图不应该被登录限制,那么你应该在文档字符串中这样做。

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 
+0

使用“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

1

有点晚了,但另一种简单的方法来解决这一问题将依靠另一装饰和添加lambda函数:

from django.contrib.auth.decorators import user_passes_test 

@user_passes_test(lambda u: u.is_anonymous) 
+0

到底是什么:“编辑必须至少有6个字符;在这篇文章中还有其他改进之处吗?”一定不行! 'u.is_anonymous'中只有缺失的括号,因此示例不正确。 – simplylizz 2017-08-13 18:36:53

+0

该示例正确并有效。你想把另外的括号放在哪里? – 2017-08-15 06:26:14

+0

哦,我检查了文档。你是对的,这是正确的,因为django 1.10+'is_anonymous'成为一个属性。但是对于以前的Django版本,它会给你总是'True',因为'is_anonymous'是方法。 – simplylizz 2017-08-16 07:56:43

1

@permission_classes([permissions.AllowAny])

相关问题