【问题标题】:Find the required permissions of Django URLs without calling them?无需调用即可找到 Django URL 所需的权限?
【发布时间】:2012-06-13 13:18:42
【问题描述】:

我的 Django 应用当前有受“permission_required()”函数保护的 URL。

此函数以三种不同的方式调用。

  1. 作为views.py 中的装饰器,带有硬编码参数。
  2. 作为普通函数,具有自动生成的参数,在自定义基于类的通用视图中。
  3. 作为在 urls.py 中调用视图的函数,带有硬编码参数。

我现在正在向应用程序添加一个菜单系统,我需要让菜单条目反映用户是否有权请求每个菜单条目的 URL。 (通过灰显或隐藏所述条目。)

有没有办法在不请求 URL 的情况下查询 URL 所需的权限?

到目前为止,我想到的唯一解决方案是将装饰器替换为无参数的“menu_permssion_required()”装饰器,并将所有权限硬编码到 Python 结构中。这似乎是倒退了一步,因为我的自定义基于类的通用视图已经自动生成了它们所需的权限。

关于如何制作一个反映当前用户的 URL 权限的菜单系统有什么建议吗?

【问题讨论】:

  • 我总是在模板中硬编码菜单,它很简单并且允许使用 {% extends %} 的上下文菜单。
  • @jplc 道歉,我无法理解您的评论与问题的关系。这是专门关于权限的。权限是跨领域的,不链接到 URL 前缀或类似的。
  • 您可以检查模板中的权限:gist.github.com/25c03f286337c66cc860 从我所见,这在 django 项目中是相当标准的,这里是有关 django perms 模块的文档:docs.djangoproject.com/en/1.0/topics/auth/#id6 不过,我的观点是,花时间为 HTML 菜单制作“系统”可能会更好地花在其他事情上。
  • @jpic 感谢您的澄清。我的目标是避免在 both 菜单模板 其他地方重复指定权限。如果我不这样做,他们在某些时候不同步,并且客户将看到不必要的错误页面。

标签: django menu authorization


【解决方案1】:

以下是如何解决您的问题的示例:

首先,创建一个装饰器包装器来代替permission_required:

from django.contrib.auth.decorators import login_required, permission_required, user_passes_test
from django.core.exceptions import PermissionDenied
from functools import wraps
from  django.utils.decorators import available_attrs

def require_perms(*perms):
    def decorator(view_func):
        view_func.permissions = perms
        @wraps(view_func, assigned=available_attrs(view_func))
        def _wrapped_view(request, *args, **kwargs):
            for perm in perms:
                return view_func(request, *args, **kwargs)
            raise PermissionDenied()
        return _wrapped_view
    return decorator

然后,用它来装饰你的视图:

@require_perms('my_perm',)
def home(request):
.....

然后,为您的菜单项添加一个标签:

from django.core.urlresolvers import resolve

def check_menu_permissions(menu_path, user):
    view = resolve(menu_path)
    if hasattr(view.func, "permissions"):
        permissions = view.func.permissions
        for perm in permissions:
            if user.has_perm(perm):
                return True # Yep, the user can access this url
            else:
                return False # Nope, the user cannot access this url
    return True #  or False - depending on what is the default behavior

最后,在您的模板中,在构建菜单树时:

<button href="{{ some_path }} {% if not check_menu_permissions some_path request.user %}disabled="disabled"{% endif %} />

注意我没有用标签测试最后一部分,但我希望你明白了。这里的神奇之处在于在装饰器中为 view_func 添加权限,然后您可以使用 resolve(path) 访问它。我不确定这在性能方面会如何表现,但毕竟这只是一个想法。

编辑:刚刚修复了示例中的一个错误..

【讨论】:

  • 谢谢,我喜欢这个总体思路。我会在月底(项目截止日期)之前让你知道它在实践中是如何工作的。
【解决方案2】:

有没有办法在不请求 URL 的情况下查询 URL 所需的权限?

User.has_perm()User.has_module_perms()

关于如何制作一个反映当前用户的 URL 权限的菜单系统有什么建议吗?

我真的很喜欢这个问题,因为它涉及使用 django 制作网站的任何人,所以我觉得它非常相关。在 2008 年我的第一个 django 项目中,我自己甚至 coded a menu "system" 都经历过。但从那以后我尝试了 Pinax,我从他们的示例项目中学到的(这么多)东西之一是它完全没有必要的膨胀.

因此,对于如何制作尊重请求用户权限的菜单“系统”,我没有任何建议可以支持。

我确实有一个关于如何制作一个尊重请求用户权限的简单菜单的建议,所以这可能不是完全无关的。

  1. 只需用纯 HTML 制作菜单,它不会经常更改以致必须生成。这也将使您的 Python 代码更简单。

  2. 添加到settings.TEMPLATE_CONTEXT_PROCESSORS'django.core.context_processors.PermWrapper'

  3. 对 User.has_perms 使用 {{ perms }} proxy

例子:

{% if perms.auth %}
    <li class="divider"></li>

    {% if perms.auth.change_user %} 
    <li>
        <a href="{% url admin:auth_user_changelist %}">{% trans 'Users' %}</a>
    </li>
    {% endif %} 

    {% if perms.auth.change_group %} 
    <li>
        <a href="{% url admin:auth_group_changelist %}">{% trans 'User groups' %}</a>
    </li>
    {% endif %} 

{% endif %} 
{# etc, etc #}

这就是我保持导航简单愚蠢不碍事的方式。但我也总是在离菜单不远的地方包含an autocomplete,以允许用户轻松导航到任何详细信息页面。所以,这就是我对 django 项目中导航的所有了解,我渴望阅读其他答案!

【讨论】:

    【解决方案3】:

    我也遇到过类似的问题,但问题更深一些。除了权限之外,我还想要基于隐藏在用户中的其他测试(即is_staffuser.units.count() &gt; 1)。在视图和模板中复制这些似乎容易出错。

    您可以内省视图对象,查看包装它的所有装饰器,并确定它们是否是检查(在我的情况下:第一个参数我是 uuser)。如果它们都通过,则允许呈现链接。

    Get all decorators wrapping a function 更详细地描述了该技术。您可以在 Django-menus 找到将其包装成方便替代 {% url %} 的应用程序。

    【讨论】:

    • 谢谢,我会看看 Django 菜单,看看它是否符合我的要求。如果我最终不得不自己编写代码(因为我使用自己的自定义权限装饰器),我会选择 Tisho 的答案,因为它明显不那么“神奇”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-28
    • 1970-01-01
    • 1970-01-01
    • 2020-01-25
    • 2016-01-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多