如何编写 Django 模板标签来进行访问控制?

发布于 2024-09-24 12:54:57 字数 1013 浏览 5 评论 0 原文

我徒劳地尝试创建一个简单的 Django 模板标签来显示或隐藏我网站上提交的评论旁边的“删除”链接。

简而言之,我想将评论对象传递给模板标签,确定当前登录的用户是否有权删除评论,然后显示或不显示链接。

我的模板中的用法如下:

{% load access_tags %}
{% if_authorized comment %}
   <a href="{% url delete_comment comment.id %}">Delete</a>
{% endif_authorized %}

请放心,如果用户有权删除评论,我还会检查相应的视图。

这种类型的标签有具体的名称吗?如果是的话,它肯定会对我的谷歌搜索有所帮助。感谢您的帮助!

更新 1:

根据我网站的工作方式,两个人可能有权删除评论:1) 评论创建者和 2) 留下评论的帖子的所有者。因此,我需要根据评论确定是否存在这些条件之一。

我不认为我可以使用 Django 的内置权限系统之类的东西,因为它要求权限“按对象类型全局设置,而不是按特定对象实例设置”。

就我而言,用户“Bob”可能有权删除评论(如果他写了评论或评论位于他创建的帖子上),但也可能不允许他删除评论(如果他正在查看对某人的评论)别人的帖子)。

更新2:

看来您无法将对象传递给模板标签,只能传递字符串:“虽然您可以使用 token.split_contents() 将任意数量的参数传递给模板标签,但参数都被解包为字符串字面意思。”我想我会传递相关评论对象的 ID 并将其拉入标签中。

我对此是错误的,只需访问传入的对象,例如:

self.comment.resolve(context).user 

vs.

self.comment.user

I'm trying, in vain, to create a simple Django template tag to either show or hide a "delete" link next to a submitted comment on my site.

In a nutshell, I want to pass the comment object to the template tag, determine if the currently logged in user is authorized to delete the comment and then either show or not show the link.

The usage in my template would be like so:

{% load access_tags %}
{% if_authorized comment %}
   <a href="{% url delete_comment comment.id %}">Delete</a>
{% endif_authorized %}

Rest assured that I also check in the appropriate view if the user is authorized to delete the comment.

Does this type of tag have a specific name? It would certainly help me with my Google searches if it did. Thanks for your help!

UPDATE 1:

The way my site works, two people are potentially authorized to delete a comment: 1) the comment creator and 2) the owner of the post where the comment was left. Because of this, I need to determine, per comment, if one of those conditions is present.

I don't think I can use something like Django's built-in permission sytem, since it requires that permissions "be set globally per type of object, no per specific object instance".

In my case, user "Bob" may have permissions to delete a comment (if he wrote it or it is on a post he created), but he also may not be allowed to delete it (if he is looking at a comment on someone else's post).

UPDATE 2:

It appears that you can't pass objects to a template tag, only strings: "Although you can pass any number of arguments to a template tag using token.split_contents(), the arguments are all unpacked as string literals." I guess I'll pass the id of the comment object in question and pull it in the tag.

I was wrong about this, just have to access the passed in object like:

self.comment.resolve(context).user 

vs.

self.comment.user

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

眼泪淡了忧伤 2024-10-01 12:54:57

好的,我就是这样做的...

标签在模板中的使用方式如下:

   {% load access_tags %}
   {% if_authorized comment.user object.user user %}
      <a href="{% url delete_comment comment.id %}">Delete</a>
   {% endif_authorized %}

模板标签文件名为“access_tag.py”,位于我的应用程序的“templatetags”目录中。这是“access_tag.py”的内容:

from django.template import Node, NodeList, TemplateSyntaxError
from django.template import Library, Variable, VariableDoesNotExist

register = Library()

def do_if_authorized(parser, token):
    """
    Outputs the contents of the block if the 'comment owner' or the 
    'page owner' is also the 'authenticated user'. As well, you can use
    an {% else %} tag to show text if the match fails.

    Takes three parameters:
      1) the comment owner
      2) the page owner
      3) the current authenticated user
    """
    bits = token.contents.split()
    if len(bits) != 4:
        raise TemplateSyntaxError("%s tag takes three arguments: \
                                   1) the comment owner \
                                   2) the page owner \
                                   3) the current authenticated user" % bits[0])
    nodelist_true = parser.parse(('else', 'endif_authorized'))
    token = parser.next_token()

    if token.contents == 'else':
        nodelist_false = parser.parse(('endif_authorized',))
        parser.delete_first_token()
    else:
        nodelist_false = NodeList()
    return IfAuthorizedNode(bits[1], bits[2], bits[3], nodelist_true, nodelist_false)

class IfAuthorizedNode(Node):
    def __init__(self, comment_owner, page_owner, authenticated_user, nodelist_true, nodelist_false):
        self.nodelist_true = nodelist_true
        self.nodelist_false = nodelist_false
        self.comment_owner = Variable(comment_owner)
        self.page_owner = Variable(page_owner)
        self.authenticated_user = Variable(authenticated_user)

    def render(self, context):
        try:
            comment_owner = self.comment_owner.resolve(context)
            page_owner = self.page_owner.resolve(context)
            authenticated_user = self.authenticated_user.resolve(context)
        except VariableDoesNotExist:
            return ''

        if comment_owner == authenticated_user or page_owner == authenticated_user:
            return self.nodelist_true.render(context)
        else:
            return self.nodelist_false.render(context)

register.tag('if_authorized', do_if_authorized)

完成。最后,使用内置的 {% if %} 标签来进行此比较是非常容易的,但由于我还有其他每个对象的授权要做,所以我将继续构建这些自定义“访问标签”。另外,模板代码看起来更加整洁:)

OK, this is how I did it...

The tag is used like this in the template:

   {% load access_tags %}
   {% if_authorized comment.user object.user user %}
      <a href="{% url delete_comment comment.id %}">Delete</a>
   {% endif_authorized %}

The template tag file is called "access_tag.py" and is in my app's "templatetags" directory. This is the contents of "access_tag.py":

from django.template import Node, NodeList, TemplateSyntaxError
from django.template import Library, Variable, VariableDoesNotExist

register = Library()

def do_if_authorized(parser, token):
    """
    Outputs the contents of the block if the 'comment owner' or the 
    'page owner' is also the 'authenticated user'. As well, you can use
    an {% else %} tag to show text if the match fails.

    Takes three parameters:
      1) the comment owner
      2) the page owner
      3) the current authenticated user
    """
    bits = token.contents.split()
    if len(bits) != 4:
        raise TemplateSyntaxError("%s tag takes three arguments: \
                                   1) the comment owner \
                                   2) the page owner \
                                   3) the current authenticated user" % bits[0])
    nodelist_true = parser.parse(('else', 'endif_authorized'))
    token = parser.next_token()

    if token.contents == 'else':
        nodelist_false = parser.parse(('endif_authorized',))
        parser.delete_first_token()
    else:
        nodelist_false = NodeList()
    return IfAuthorizedNode(bits[1], bits[2], bits[3], nodelist_true, nodelist_false)

class IfAuthorizedNode(Node):
    def __init__(self, comment_owner, page_owner, authenticated_user, nodelist_true, nodelist_false):
        self.nodelist_true = nodelist_true
        self.nodelist_false = nodelist_false
        self.comment_owner = Variable(comment_owner)
        self.page_owner = Variable(page_owner)
        self.authenticated_user = Variable(authenticated_user)

    def render(self, context):
        try:
            comment_owner = self.comment_owner.resolve(context)
            page_owner = self.page_owner.resolve(context)
            authenticated_user = self.authenticated_user.resolve(context)
        except VariableDoesNotExist:
            return ''

        if comment_owner == authenticated_user or page_owner == authenticated_user:
            return self.nodelist_true.render(context)
        else:
            return self.nodelist_false.render(context)

register.tag('if_authorized', do_if_authorized)

Done. In the end, it would have been pretty easy to just use the built-in {% if %} tag to do this comparison, but since I'll have other per-object authorizations to do, I will continue to build out these custom "access_tags". Plus, the template code looks so much tidier :)

三五鸿雁 2024-10-01 12:54:57

已经存在一个旨在做您想做的事情的项目。

django-authority 允许对模板中的权限进行细粒度控制。

Django 1.2 还在模板中包含用户权限

There already exists a project that aims to do what you would like to do.

django-authority allows for fine grain control over permissions in templates.

Django 1.2 also contains user permissions in templates, too.

心奴独伤 2024-10-01 12:54:57

怎么样...创建一个自定义标签 在上下文中写入一个变量,然后使用 {% if %} 测试该变量,

就像这样:

{% check_access comment %}
{% if has_access %}
    <a href="{% url delete_comment comment.id %}">Delete</a>
{% endif %}

当然是“check_access”标签将在上下文中写入“has_access”。

祝你好运

how about this... create a custom tag that writes a variable in the context, then test that variable using {% if %}

it'd be something like this:

{% check_access comment %}
{% if has_access %}
    <a href="{% url delete_comment comment.id %}">Delete</a>
{% endif %}

of course the "check_access" tag would write the "has_access" in the context.

Good Luck

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文