如何避免django的权限字符串

时间:2016-10-10 08:46:41

标签: django django-permissions

根据文档,可以像这样创建和使用自定义权限:

class Task(models.Model):
    ...
    class Meta:
        permissions = (
            ("view_task", "Can see available tasks"),
        )

使用权限:

user.has_perm('app.view_task')

来源:https://docs.djangoproject.com/en/1.10/topics/auth/customizing/#custom-permissions

如果权限字符串中存在拼写错误。例如:我使用user.has_perm('app.view_tasks'),然后就会注意到这个拼写错误。

目标1

如果不使用现有权限,我想获得异常或警告。

目标2

为了首先避免打字错误,我希望有常量:user.PERM_APP_VIEW_TASKS或类似的东西。

2 个答案:

答案 0 :(得分:2)

目标1

从我的has_perm文件中覆盖ModelBackend类的backends.py方法:

import logging
from difflib import get_close_matches
from django.conf import settings
from django.contrib.auth.backends import ModelBackend


class ModelBackendHelper(ModelBackend):
    def has_perm(self, user_obj, perm, obj=None):
        if not user_obj.is_active:
            return False
        else:
            obj_perms = self.get_all_permissions(user_obj, obj)
            allowed = perm in obj_perms

            if not allowed:
                if settings.DEBUG:
                    similar = get_close_matches(perm, obj_perms)

                    if similar:
                        logging.warn("{0} not found, but is similar to: {1}".format(perm, ','.join(similar)))

            return allowed

工作原理:

has_perm的逻辑相同,但如果settings.DEBUGTrue且找到perm的相似版本,则输出级别为WARN的警告日志消息:< / p>

WARNING:root:myapp.view_tasks not found, but is similar to: myapp.view_task

更改AUTHENTICATION_BACKENDSsettings.py的值:

AUTHENTICATION_BACKENDS = ['myapp.backends.ModelBackendHelper']

这可以在生产环境和开发环境中使用,但我个人不会将其包含在生产站点中,我希望当一切都进入生产权限时,合并。

目标2

权限属于模型,为了保持这种权限,我重复使用Meta中定义的权限:

from django.db import models


class Task(models.Model):
    name = models.CharField(max_length=30)
    description = models.TextField()

    class Meta:
        permissions = (
            ("view_task", "Can see available tasks"),
        )


def _get_perm(model, perm):
    for p in model._meta.permissions:
        if p[0] == perm:
            return p[0]
    err = "Permission '{0}' not found in model {1}".format(perm, model)
    raise Exception(err)


def format_perm(perm):
    return '{0}.{1}'.format(__package__, perm)


def get_perm(model, type):
    return format_perm(_get_perm(model, type))


PERM_APP_VIEW_TASK = get_perm(Task, "view_task")

可以使用get_perm或快捷方式PERM_APP_VIEW_TASK访问权限:

models.PERM_APP_VIEW_TASK
# or
get_perm(Task, "view_task")
# or
format_perm(_get_perm(Task, "view_task"))

如果搜索丢失的权限get_perm,则会引发Exception

PERM_APP_VIEW_TASK = get_perm(Task, "add_task")

消息:

Exception: Permission 'add_task' not found in model <class 'myapp.models.Task'>

答案 1 :(得分:0)

目标1

创建自定义装饰器:

警告!未经测试的代码!!!!!

@permission_required
def assert_permission(permission):
    def real_decorator(original_function):
        def wrapper(request, *args, **kwargs):
            permission_object = Permission.objects.filter(codename=permission)
            if not permission_object.exists():
                raise ValueError("This permission does not exist!")
            original_function(request, *args, **kwargs)
        return wrapper
    return real_decorator

目标2

向模型类添加常量,并在询问特定权限时引用它们。 例如:

class Task(models.Model):
MY_PERMISSION_CONSTANT = 'app.view_task'
...
class Meta:
    permissions = (
        (MY_PERMISSION_CONSTANT, "Can see available tasks"),
    )

@permission_required(Task.MY_PERMISSION_CONSTANT)
def some_view(request):
  pass