콘텐츠 유형이나 모델을 정의하지 않고 Django 권한을 어떻게 사용할 수 있습니까?


84

권한 기반 시스템을 사용하여 Django 애플리케이션 내에서 특정 작업을 제한하고 싶습니다. 이러한 작업은 특정 모델 (예 : 응용 프로그램의 섹션 액세스, 검색 ...)과 관련 될 필요가 없습니다. 따라서 모델에 설치된 콘텐츠 유형에 대한 참조가 필요 하기 때문에 스톡 권한 프레임 워크를 직접 사용할 수 없습니다 Permission.

나만의 권한 모델을 작성할 수 있지만 다음과 같이 Django 권한에 포함 된 모든 기능을 다시 작성해야합니다.

django-authoritydjango-guardian 과 같은 일부 앱을 확인 했지만 객체 별 권한을 허용하여 모델 시스템과 더욱 결합 된 권한을 제공하는 것 같습니다.

프로젝트에 대한 모델 ( User및 제외 Group)을 정의하지 않고이 프레임 워크를 재사용 할 수있는 방법이 있습니까?

답변:


57

Django의 Permission모델 에는 ContentType인스턴스 가 필요 합니다 .

한 가지 방법은 ContentType모델과 관련이없는 더미 를 만드는 것입니다 ( app_labelmodel필드는 모든 문자열 값으로 설정할 수 있음).

모든 것을 깔끔하고 멋지게 만들고 싶다면 더미의 모든 추악한 세부 사항을 처리하고 "모델없는"권한 인스턴스를 만드는 Permission 프록시 모델 을 만들 수 있습니다 ContentType. Permission실제 모델과 관련된 모든 인스턴스 를 필터링하는 사용자 지정 관리자를 추가 할 수도 있습니다 .


3
괜찮 으시면 제 구현으로 답변을 완료하겠습니다.
Chewie

안타깝게도 편집 내용을 검토 할 평판이 충분하지 않아 승인 할 수 없습니다 (+ 2k 요청). 다른 사용자가 귀하의 편집을 거부하고 있으므로 다른 답변으로 추가하는 것이 좋습니다 (내 찬성 투표가 있습니다!). 다시 한 번 감사드립니다.
Gonzalo

1
이상 하네. 답변에 대한 완성이므로 편집하는 것이 좋습니다. 어쨌든 다른 대답에 넣었습니다.
Chewie

138

아직 찾고 계신 분들을 위해 :

데이터베이스 테이블없이 보조 모델을 생성 할 수 있습니다. 이 모델은 필요한 모든 권한을 프로젝트에 가져올 수 있습니다. ContentType을 다루거나 명시 적으로 Permission 개체를 만들 필요가 없습니다.

from django.db import models
        
class RightsSupport(models.Model):
            
    class Meta:
        
        managed = False  # No database table creation or deletion  \
                         # operations will be performed for this model. 
                
        default_permissions = () # disable "add", "change", "delete"
                                 # and "view" default permissions

        permissions = ( 
            ('customer_rights', 'Global customer rights'),  
            ('vendor_rights', 'Global vendor rights'), 
            ('any_rights', 'Global any rights'), 
        )

마우스 오른쪽 후 manage.py makemigrationsmanage.py migrate는 다른 같은 이러한 권한을 사용할 수 있습니다.

# Decorator

@permission_required('app.customer_rights')
def my_search_view(request):
    …

# Inside a view

def my_search_view(request):
    request.user.has_perm('app.customer_rights')

# In a template
# The currently logged-in user’s permissions are stored in the template variable {{ perms }}

{% if perms.app.customer_rights %}
    <p>You can do any customer stuff</p>
{% endif %}

2
그게 천재 야, 내 하루를 구해줘!
Reorx

2
manage.py migrate를 실행 한 후 변경된 사항이 없습니다 ... 새로운 권한이 표시되지 않습니다. (
Agey

2
프로젝트 (INSTALLED_APPS)에 앱을 추가하셨습니까?
Dmitry

2
이 대답은 완벽합니다. 또한 default_permissions를 [] ed하고, 모델의 save ()에서 NotImplementedError를 발생 시켰으며, 관리되지 않는 모델이 진정으로이 권한에 대한 것이면 has _ * _ permission ()이 False를 반환하도록하는 것을 고려할 수 있습니다.
Douglas Denhartog

4
Meta 클래스에 다음을 추가하는 것이 좋습니다 default_permissions = ().. 이렇게하면 Django가이 모델에 대한 기본 추가 / 변경 / 삭제 /보기 권한을 자동으로 생성하는 것을 방지 할 수 있으며,이 접근 방식을 사용하는 경우 대부분 불필요합니다.
Jordan

51

다음 곤잘로의 조언을 , 내가 사용하는 프록시 모델사용자 정의 관리자를 더미 콘텐츠 형식으로 내 "modelless"권한을 처리 할 수 있습니다.

from django.db import models
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType


class GlobalPermissionManager(models.Manager):
    def get_query_set(self):
        return super(GlobalPermissionManager, self).\
            get_query_set().filter(content_type__name='global_permission')


class GlobalPermission(Permission):
    """A global permission, not attached to a model"""

    objects = GlobalPermissionManager()

    class Meta:
        proxy = True

    def save(self, *args, **kwargs):
        ct, created = ContentType.objects.get_or_create(
            name="global_permission", app_label=self._meta.app_label
        )
        self.content_type = ct
        super(GlobalPermission, self).save(*args, **kwargs)

10
코드 덕분에이 코드를 사용하는 방법에 대한 예제도 보여 주면 좋을 것입니다.
Ken Cochrane 2013 년

2
모델 허가는 어디에 있어야합니까?
Mirat Can Bayrak 2013 년

4
GlobalPermission을 생성하려면 : from app.models import GlobalPermission gp = GlobalPermission.objects.create (codename = 'can_do_it', name = 'Can do it') 이것이 실행되면 다른 권한과 마찬가지로 사용자 / 그룹에 해당 권한을 추가 할 수 있습니다. .
Julien Grenier 2014

3
@JulienGrenier Django 1.8에서 코드가 깨졌습니다 FieldError: Cannot resolve keyword 'name' into field. Choices are: app_label, id, logentry, model, permission..
maciek 2015-04-30

2
경고 : 최신 버전의 Django (최소 1.10)는 "get_queryset"메서드를 재정의해야합니다 ( "query"와 "set 단어 사이에 _가 없음에 유의하십시오).
Lobe

10

Django 1.8에서 Chewie의 답변을 수정했습니다. 이는 몇 가지 의견에서 요청되었습니다.

릴리스 정보에 다음과 같이 나와 있습니다.

django.contrib.contenttypes.models.ContentType의 이름 필드는 마이그레이션에 의해 제거되고 속성으로 대체되었습니다. 이는 더 이상이 필드로 ContentType을 쿼리하거나 필터링 할 수 없음을 의미합니다.

따라서 GlobalPermissions에서 사용하지 않는 ContentType의 참조에서 '이름'입니다.

수정하면 다음과 같은 결과가 나타납니다.

from django.db import models
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType


class GlobalPermissionManager(models.Manager):
    def get_queryset(self):
        return super(GlobalPermissionManager, self).\
            get_queryset().filter(content_type__model='global_permission')


class GlobalPermission(Permission):
    """A global permission, not attached to a model"""

    objects = GlobalPermissionManager()

    class Meta:
        proxy = True
        verbose_name = "global_permission"

    def save(self, *args, **kwargs):
        ct, created = ContentType.objects.get_or_create(
            model=self._meta.verbose_name, app_label=self._meta.app_label,
        )
        self.content_type = ct
        super(GlobalPermission, self).save(*args)

GlobalPermissionManager 클래스는 변경되지 않았지만 완전성을 위해 포함되었습니다.


1
이것은 syncdb에서 django가 "name"필드가 null 일 수 없다고 주장하기 때문에 django 1.8에서는 여전히 수정되지 않습니다.
Armita 2015-08-22

그것은 나를 위해 일했지만 내 프로젝트에 여전히 장고가 아닌 레거시 항목으로 인해 마이그레이션을 사용하지 않습니다. 1.8에 이름 필드가있을되어 있지 않기 때문에 당신이 이전 장고에서 업그레이드
rgammans

4

이것은 대체 솔루션입니다. 먼저 스스로에게 물어보십시오. DB에 실제로 존재하지만 권한 보유를 제외하고는 결코 사용되지 않는 더미 모델을 생성하지 않는 이유는 무엇입니까? 좋지는 않지만 타당하고 직접적인 해결책이라고 생각합니다.

from django.db import models

class Permissions(models.Model):

    can_search_blue_flower = 'my_app.can_search_blue_flower'

    class Meta:
        permissions = [
            ('can_search_blue_flower', 'Allowed to search for the blue flower'),
        ]

위의 솔루션은 Permissions.can_search_blue_flower리터럴 문자열 "my_app.can_search_blue_flower"를 사용하는 대신 소스 코드에서 변수 를 사용할 수 있다는 이점이 있습니다 . 이것은 IDE에서 오타가 적고 자동 완성이 더 많다는 것을 의미합니다.


1
왠지 사용 managed=False하지 Permissions.can_search_blue_flower않습니까?
Sam Bobel

@ SamBobel 네, 당신이 옳을 수 있습니다. 지난번에 "추상"을 시도한 것 같습니다.
guettli

1

proxy model이를 위해 더미 콘텐츠 유형과 함께 사용할 수 있습니다 .

from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType


class CustomPermission(Permission):

    class Meta:
        proxy = True

    def save(self, *args, **kwargs):
        ct, created = ContentType.objects.get_or_create(
            model=self._meta.verbose_name, app_label=self._meta.app_label,
        )
        self.content_type = ct
        super(CustomPermission, self).save(*args)

이제 모델 의 권한 name과 권한 만 사용하여 권한을 만들 수 있습니다 .codenameCustomPermission

 CustomPermission.objects.create(name='Can do something', codename='can_do_something')

그리고 이와 같이 템플릿에서 사용자 지정 권한 만 쿼리하고 표시 할 수 있습니다.

 CustomPermission.objects.filter(content_type__model='custom permission')
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.