在Django中发送自定义权限拒绝消息

14 投票
5 回答
15661 浏览
提问于 2025-04-18 17:45

我正在使用Django中的PermissionDenied,当用户没有权限访问某个页面时,就会显示403.html这个页面。

我们有很多不同类型的页面,比如产品页面用户页面用户联系信息所有者信息等等。

我想在PermissionDenied中添加一个自定义消息,告诉用户为什么他们不能查看这个页面。我希望在403.html中添加以下动态消息。

You have are trying to `View a Product (id:3094384)` while having a `Trail` account. You are not authorized to view this product. 

还有

 You have are trying to `View a Customer (id:48)` which is Private. You are not authorized to view this User. 

等等。

这是我的代码

elif role.id == Project.ROLE_SALES and not project.sales_person_id == user_id:
            raise PermissionDenied

html

<body class="error-page">

<!--  content -->
<section>
    <div class="error403">
        <h1>403</h1>
    </div>
    <p class="description">Oops! Request forbidden...</p>

    <p>Sorry, it appears the page you were looking for is forbidden and not accessible. If the problem persists, please
        contact web Administrator.</p>


# HERE I WANT TO SHOW DYNAMIC MESSAGE. 



    <a href="{{ request.META.HTTP_REFERER }}" class="btn btn-danger403 btn-primary btn-large" >
        Go Back </a>
{{ except }}
</section>



<script src="{% static 'js/jquery.min.js' %}"></script>
<script src="{% static 'js/bootstrap.js' %}"></script>
</body>

可能性

raise PermissionDenied("Custom message")

或者

能否给PermissionDenied传递一个上下文?

有什么建议吗。

5 个回答

0

我也遇到同样的问题。

django 1.9 版本中,这个功能是内置的。在早期的 django 版本中,我们可以使用 sys.exc_info(),所以接下来的步骤就是重新利用整个默认的 permission_denied 处理器,来添加我们的异常。

# urls.py
...
handler403 = 'project.views.errors.permission_denied'
...

# views/errors.py
import sys

from django import http
from django.template import Context, TemplateDoesNotExist, loader
from django.views.decorators.csrf import requires_csrf_token


@requires_csrf_token
def permission_denied(request, template_name='403.html'):
    _, value, _ = sys.exc_info()

    try:
        template = loader.get_template(template_name)
    except TemplateDoesNotExist:
        return http.HttpResponseForbidden('<h1>403 Forbidden</h1>', content_type='text/html')
    return http.HttpResponseForbidden(
        template.render(request=request, context={'exception': force_text(value)})
    )

# templates/403.html
...
{{ exception }}
...
1

如果你在使用基于类的视图(CBV),或者任何扩展了 AccessMixin 的东西,你可以设置 permission_denied_message 属性,或者重写 get_permission_denied_message 方法。

举个例子:

from django.conf import settings

class MyView(ListView):
    permission_denied_message = 'Hooo!'

    def get_permission_denied_message(self):
        perms = self.get_permission_required()
        if settings.DEBUG:
            for perm in perms:
                if not self.request.user.has_perm(perm):
                    return 'Permission denied: ' + str(perm)
        return ''

然后,在你的模板中:

{% if exception and debug %}
    <h3 class="font-bold">{{ exception }}</h3>
{% endif %}
1

你可以这样试试:

class SomeException(Exception):
    message = 'An error occurred.'

    def __init__(self, message):
        self.message = message

    def __str__(self):
        return repr(self.message)

#usage
 raise SomeException("Hello, you have an exception here")

还有一种发送消息到模板的方法是:

if not request.user.is_staff: #or your condition
   context['flash_message']= "permission error occurred"
   retrun render_to_response('template.html', context)

# template
<!-- I am using bootstrap here -->
<div class="alert alert-{{ flash_message_type }} flash_message hide">
    {{ flash_message | safe }}
</div>

<script>
...
if($.trim($(".flash_message").html()) != ''){
        $(".flash_message").slideDown();
        setTimeout(function(){
            $(".flash_message").slideUp();
        }, 5000);
    };
</script>
3

我遇到了同样的问题,后来我用Django的消息框架解决了这个问题,这样可以把自定义的信息传递到模板里。

https://docs.djangoproject.com/en/1.8/ref/contrib/messages/

我的具体例子是:

from django.contrib import messages
...
messages.error(request, 'The submission deadline has passed.')
raise PermissionDenied

然后可以按照文档中的说明在模板里输出这些消息。

27

这个回答可能对你来说来得有点晚。不过还是给你分享一下。

你可以在你的Django代码中使用下面的内容:

raise PermissionDenied("Custom message")

然后在403.html模板中用下面的代码来显示自定义消息:

{% if exception %}
  <p>{{ exception }}</p>
{% else %}
  <p>Static generic message</p>
{% endif %}

传递给'PermissionDenied'的消息字符串可以在模板上下文中使用,具体内容可以参考Django的文档 - https://docs.djangoproject.com/en/stable/ref/views/#http-forbidden-view

撰写回答