DjangoはObjectレベルの権限制御を実現する-django-guardian

9657 ワード

私のシリーズblog「Djangoに組み込まれた権限制御」では、DjangoのデフォルトではObjectレベルの権限制御は提供されておらず、アーキテクチャに口を残しているだけであることが明らかになった.このblogでは、Object level permissionを実現するために、簡単に流行しているDjangoコンポーネントdjango-guardianを検討します.
インストール構成django-guardian
まずdjango-guardianをインストールする必要があります.一般的にvirtualenvで仮想環境を作成するのが好きです.
>>virtualenv --distribute venv

>>source venv/bin/activate

>>pip install Django

>>pip install django-guardian


これで、必要なdjango-guardianがインストールされます.
次にDjangoにそれを知らせる必要がありますINSTALLED_APPS変数にguardianを加える:
INSTALLED_APPS = (

    'guardian',

)


そして、『Djangoに内蔵されている権限制御』の5番目の文章をよく読んだ読者は、AUTHENTICATIONにbackendを追加する必要があると推測すべきだ.BACKENDSでは、djangoがオブジェクトに対する権限制御を持つようになります.
AUTHENTICATION_BACKENDS = (

    'django.contrib.auth.backends.ModelBackend', # django   backend

    'guardian.backends.ObjectPermissionBackend',

)


guardianでは、匿名のユーザーAnoymousUserのObjectレベルに対する権限制御もサポートされています.このようなニーズは、匿名の発言を許可するフォーラムやblogシステムなど、一般的です.これを行うにはsettingsに追加する必要があります.
ANONYMOUS_USER_ID=-1

次にpython manage syncdb.を実行します.実行が完了すると、AnonymouseUserというUserインスタンスが作成されます.
以上の点でguardianがインストールされ、使用が開始されます.
 オブジェクト権限の設定と使用:
まず、オブジェクト権限の設定と使用はもちろんですが、guardianは簡単な方法を提供しています.
guardian.shortcuts.assign(perm,user_or_group,obj=None)は、3つのパラメータを受け入れます.
  • perm、このパラメータは文字列であり、ライセンスを表し、フォーマットは.または.ただし、3番目のパラメータがNoneの場合は.フォーマット.そこで.フォーマット.注意appはappのフルパスではなく、最後のレベルのモジュール名です.この点とINSTALL_アプリの中のappは全経路が異なり、もしあなたのapp moduleが1級でなければ、ここは必ず注意してください.
  • user_or_group、このパラメータはUserまたはGroupタイプのオブジェクトです.
  • obj、このパラメータは関連するオブジェクトです.パラメータ変更は省略可能で、省略するとModel権限が付与されます.

  • この方法により、.フォーマットの文字列は、ユーザUserまたはグループGroupに権限を付与します.3番目のパラメータを入力しない場合は、User.user_として使用できます.permissions.add(permissioninstance)のショートカット.
    次に、モデル・レベルに付与する権限を示します.
    from guardian.shortcuts import assign
    
    user = User.objects.create(username='liuyong')
    
    assign('app.view_task', user)
    
    user.has_perm('app.view_task') >>True
    
    

    モデル・レベルの権限が付与されると、そのモデルのオブジェクト・レベルのすべての権限が付与されるので、オブジェクト・レベルから設定し、割り当てたばかりの権限を空にしてからオブジェクト権限を設定する必要があります.
    user = User.objects.get(username='liuyong')
    
    user.user_permissions.clear()
    
    task = Task.objects.create(summary='Some job', content='')
    
    assign('app.view_task', user, task)
    
    user = User.objects.get(username='liuyong')#    
    
    user.has_perm('app.view_task',task)
    
    >>True
    
    user.has_perm('app.view_task')#          
    
    >>False
    
    

    グループを設定することで、ユーザーに適切な権限を与えることもできます.
    >>> group = Group.objects.create(name='employees')
    
    >>> assign('change_task', group, task)
    
    >>> user.has_perm('change_task', task)
    
    False
    
    >>> # user   employees    ,      
    
    >>> user.groups.add(group)
    
    >>> user.has_perm('change_task', task)
    
    True
    
    

    次に、あるオブジェクトに対するユーザーのライセンスを削除します.guardian.shortcutsモジュールのremove_を使用する必要があります.perm()関数.この関数の署名はassignと同じで、3つです.
    guardian.shortcuts.remove_perm(perm,user_or_group=None, obj=None)
    サンプルコード:
    >>> from guardian.shortcuts import remove_perm
    
    >>> remove_perm('change_site', user, site)
    
    >>> user = User.objects.get(username='joe') #  user    
    
    >>> joe.has_perm('change_site', site)
    
    False
    
    

      
     以上、guadianのインストール構成と基本的な使用方法について説明します.DjangoのViewで使用できるhelper関数について説明します.
    GuardianのViewでの使用
    Djangoのuser.hasを除いてperm法に加えてguardianは、私たちの生活をより楽にするためのいくつかのヘルプ関数を提供しています.
    guardian.shortcuts.get_perms(user_or_group,obj)
    このメソッドは、objオブジェクトに対するuserオブジェクトのすべての権限を返します.この行数は、userオブジェクトまたはグループオブジェクト、関連オブジェクトの2つのパラメータを受け入れます.
    たとえば、
    'permcodename' in get_perms(group,obj)は、groupにhas_がないため、グループにこの権限があるかどうかを判断する.permメソッド.
    guardian.shortcuts.get_objects_for_user(user, perms, klass=None, use_groups=True, any_perm=False)
    この関数は、ユーザーの下で指定したpermリスト内のすべてのオブジェクトを取得します.たとえば、あるユーザーに編集権限を持つすべての投稿を取得します.
    get_objects_for_user(user,'app.change_post')
    
    >>        
    
    

    guadian.core.ObjectPermissionChecker
    この方法は、userとgroupに対する権限に関連するアクセス方法を提供する権限を判断するためのパッケージであり、主にhas_がある.perm(perm,obj)とget_perms(obj)の2つの方法.また、キャッシュメカニズムを提供し、権限を複数回検索するときに使用できます.
    >>> epser = User.objects.get(username='esper')
    
    >>> site = Site.objects.get_current()
    
    >>> from guardian.core import ObjectPermissionChecker
    
    >>> checker = ObjectPermissionChecker(esper) #         group  
    
    >>> checker.has_perm('change_site', site)
    
    True
    
    >>> checker.has_perm('add_site', site) #             
    
    False
    
    >>> checker.get_perms(site)
    
    [u'change_site']
    
    

    viewのdecoratorを使う
    decoratorを使用してコードを減らすことができます.
    次のコードでは、decoratorによってview関数へのアクセスを制御する方法を示します.私たちがしなければならないのは、name=foobarsを持つGroupオブジェクトだけがauth.change_を持つことです.group権限のユーザは、このview関数を実行することができます.そうしないと、ステータスコード403のResponseオブジェクトが返されます.
    >>> joe = User.objects.get(username='joe')
    
    >>> foobars = Group.objects.create(name='foobars')
    
    >>>
    
    >>> from guardian.decorators import permission_required_or_403
    
    >>> from django.http import HttpResponse
    
    >>>
    
    >>> @permission_required_or_403('auth.change_group',
    
    >>>     (Group, 'name', 'group_name'))
    
    >>> def edit_group(request, group_name):
    
    >>>     return HttpResponse('some form')
    
    >>>
    
    >>> from django.http import HttpRequest
    
    >>> request = HttpRequest()
    
    >>> request.user = joe
    
    >>> edit_group(request, group_name='foobars')
    
    <django.http.HttpResponseForbidden object at 0x102b43dd0>
    
    >>>
    
    >>> joe.groups.add(foobars)
    
    >>> edit_group(request, group_name='foobars')
    
    <django.http.HttpResponseForbidden object at 0x102b43e50>
    
    >>>
    
    >>> from guardian.shortcuts import assign
    
    >>> assign('auth.change_group', joe, foobars)
    
    <UserObjectPermission: foobars | joe | change_group>
    
    >>>
    
    >>> edit_group(request, group_name='foobars')
    
    <django.http.HttpResponse object at 0x102b8c8d0>
    
    >>> #   ,         ,     view         。
    
    

    Guardianのテンプレートでの使用 
     Djangoと同様に、インタフェース上で権限制御を行い、異なるインタフェースを表示する必要があります.
    Guardianには次のラベルがあります.
    get_obj_perms
    guardian_をロードする必要がありますtagsラベルライブラリは、guardianラベルを使用する必要があるテンプレートの上で、最近のものを参照します.
    {% load guardian_tags %}

    ラベルの形式は次のとおりです.
    {% get_obj_perms user/group for obj as "context_var" %}

    例コードは次のとおりです.
    {% get_obj_perms request.user for flatpage as "flatpage_perms" %}
    
    
    
    {% if "delete_flatpage" in flatpage_perms %}
    
        <a href="/pages/delete?target={{ flatpage.url }}">Remove page</a>
    
    {% endif %}
    
    

     
    孤児対象許可(Orphaned object permissions):
     孤児対象者の許可
    孤児の許可とは、無駄な許可だ.多くの場合、大丈夫かもしれませんが、一度発生すると、結果は非常に深刻になる可能性があります.
    Guardianは、あるユーザがモデルオブジェクトに対して権限を持つレコードを記録するために使用される場合、UserObjectPermissionおよびGroupObjectPermissionオブジェクトレコードを使用します.ここでobjectへの参照はcontenttypeオブジェクト(そのモデルクラスであることを示す)とpkプライマリ・キーであり,ユーザに対してはUserテーブルへの外部キー参照である.
    例えば、Aの相手がいます.私たちは権限設定を通じてjoeユーザーがそのオブジェクトに対して編集権限を持っていることを設定します.ある日突然、ユーザーjoeが削除されました.我々が割り当てたUserObjectPermissionオブジェクトは、依然としてデータベース内にあり、joeにはAに対する編集権限が記録されていることがわかります.またある日、ユーザーがjoeとしてユーザーを登録しました.以前の記録のため、joeユーザーはAに対する編集権限を持っていた.このjoeは彼joeではなく、私たちは大きな間違いを犯しました!
    例えば、あるオブジェクトを削除したとき、そのオブジェクトの何らかの権限がユーザーに与えられた場合、この権限の記録は失効します.削除したオブジェクトと同じモデルクラスであり、プライマリ・キーが以前のオブジェクトと同じである場合、ユーザーは権限を持つべきでないオブジェクトに権限を持つ可能性があります.ほほほ、ちょっと回りくどいですが、分かりやすいはずです.
    したがって、Userと関連するObjectを削除するときは、関連するすべてのUserObjectPermissionオブジェクトとGroupObjectPermissionオブジェクトを削除する必要があります.
    この方法を解決するには、3つの方法があります.1つは明示的な符号化であり、1つは、それによって提供されるカスタムdjangoコマンドです.
    $ python manage.py clean_orphan_obj_perms
    
    Removed 11 object permission entries with no targets
    
    

    もう1つはguardian.utils.clean_を定期的に呼び出すことですorphan_obj_perms()
    この関数は、削除されたオブジェクトの数を返します.pythonの世界では、celeryを使用してこのタスクを定期的にスケジュールすることができます.
    しかし、カスタムコマンドと定期的なスケジューリングは、合理的な生産環境の解決策ではありません.本当に解決するには、手動で符号化する必要があります.最も優雅な方法はpostを加えることです.delete signalはUserまたはObjectオブジェクトに、オブジェクトのサンプルコードは以下のとおりです.
    from django.contrib.auth.models import User
    
    from django.contrib.contenttypes.models import ContentType
    
    from django.db.models import Q
    
    from django.db.models.signals import pre_delete
    
    from guardian.models import UserObjectPermission
    
    from guardian.models import GroupObjectPermission
    
    from school.models import StudyGroup
    
    
    
    
    
    def remove_obj_perms_connected_with_user(sender, instance, **kwargs):
    
        filters = Q(content_type=ContentType.objects.get_for_model(instance),
    
            object_pk=instance.pk)
    
        UserObjectPermission.objects.filter(filters).delete()
    
        GroupObjectPermission.objects.filter(filters).delete()
    
    
    
    pre_delete.connect(remove_obj_perms_connected_with_user, sender=StudyGroup)
    
    

    これで終わりますが、必要なコードを書く必要があります.