Django-guardian: Tambahkan peran

Dibuat pada 16 Jan 2011  ·  14Komentar  ·  Sumber: django-guardian/django-guardian

Pertama-tama, izinkan saya menjelaskan mengapa kami tidak menambahkan peran sejak awal. Singkatnya, kebijakan Django adalah memasukkan baterai yang sederhana namun dikerjakan dengan baik. Django.contrib.auth adalah contoh terbaik. Berapa kali orang perlu bertukar auth dengan implementasinya sendiri? Saya percaya tidak begitu banyak. wali dimaksudkan untuk menjadi semacam "ekstensi" untuk aplikasi auth, dengan antarmuka yang waras & sederhana. Dan itu saja. Tidak banyak fungsi tambahan yang disertakan (kecuali beberapa fungsi pintasan - tetapi ini merujuk ke bagian "waras").

Sekarang, ada apa dengan peran? Semua yang selalu mereka butuhkan? Bahkan, saya percaya tidak. Sama dengan kelompok, sungguh. Pengguna diperlukan karena merupakan entitas fundamental untuk sebagian besar dari semua aplikasi.

Ok, ini dia, v1.0 hampir keluar. Jadi untuk v1.1, dukungan peran mungkin merupakan fitur yang paling penting. Namun, dalam pandangan saya, itu harus "opsional" dalam beberapa cara.

API change Enhancement

Semua 14 komentar

+1 Tapi saya setuju peran adalah sesuatu yang hampir tidak pernah diperlukan di sebagian besar aplikasi yang ditulis dalam Django.
Sesekali seseorang seperti kami mencoba untuk mengimplementasikan sebuah aplikasi (sistem manajemen dokumen kustom) yang Django tidak benar-benar dibuat untuknya, dan ketika Anda memiliki banyak perm, Anda mulai berpikir tentang peran :) peran dan pewarisan adalah dua hal yang harus membuatnya menjadi v1.1

bagian opsionalnya mudah. sama seperti menggunakan Django tidak membuat Anda menggunakan grup, jangan membuat orang harus mendefinisikan peran.

thx untuk aplikasinya btw.
Abu

+1 untuk peran, tergantung pada implementasi.

+1 untuk peran dan warisan

Saya menganggap peran sebagai "grup izin", saya tidak tahu apakah ini sama untuk Anda. Dengan kelas peran ini, menetapkan banyak izin menjadi lebih mudah. Saya menyarankan untuk mengimplementasikan ini menggunakan set Python untuk mengurangi satu peran ke peran lain, atau mendapatkan persimpangan, dan seterusnya:

http://docs.python.org/library/stdtypes.html#set -types-set-frozenset
http://en.wikibooks.org/wiki/Python_Programming/Sets

+1 untuk peran, warisan, dan opsional

Halo semua,
Saya salah satu orang yang membutuhkan - atau ingin memiliki - izin objek berbasis peran.

Saya mengerti dari diskusi ini bahwa untuk alasan yang sangat bagus itu bukan prioritas untuk django-guardian. Jadi saya akan membuat aplikasi saya sendiri. Namun, saya pikir sebagian besar fitur dan komponen Django-guardian, baik-baik saja dan jika memungkinkan, saya tidak ingin menemukan kembali roda tetapi menggunakannya kembali. Jadi pertanyaan saya adalah, jika Anda bersedia membuat Django-guarding sedikit lebih bisa dipasang. Misalnya (itu hanya hal pertama yang muncul di benak saya, saat membaca kode): buat pengaturan untuk ObjectPermissionChecker, yang akan memungkinkan aplikasi lain untuk mengganti kelas Checker dengan sesuatu yang menangani peran?

apa yang kalian pikirkan?

Terima kasih
Juergen

Hej @schacki , itu sebenarnya ide yang cukup bagus. Pengujian kemungkinan besar akan gagal untuk kelas pemeriksa non-default tetapi kami dapat menandainya atau memastikannya dijalankan hanya dengan pemeriksa default. Bisakah Anda membuat tugas khusus untuk itu?

Saya akan membuat kelas pemeriksa non-default apa pun bukan bagian dari Django-guardign tetapi dari aplikasi "lainnya" - jadi itu adalah tugas aplikasi lain ke kelas pemeriksa non-default. Tolong izinkan saya melakukan analisis yang lebih menyeluruh tentang apa yang mungkin perlu diadaptasi dan diubah sebelum membuka tugas. Dengan "tugas" saya berasumsi maksud Anda masalah terpisah? btw: mungkin butuh beberapa minggu sebelum ini bergerak maju.

bantuan proyek [1] ini dengan apa saja?

[1] https://github.com/vintasoftware/django-role-permissions

Disalin teks berikut oleh @suriya dari #330:

Ada beberapa diskusi di #23 terakhir tentang menambahkan peran dukungan di django-guardian. Namun, itu tidak bergerak jauh. Ini mungkin karena menambahkan peran ke django-guardian sepertinya tugas yang sangat kompleks.

Saya pikir saya punya proposal yang sangat sederhana. Saya ingin mengajukannya dan jika ada minat, implementasikan. Saat ini, saya memiliki garpu Django-guardian saya sendiri yang memiliki fungsi ini. Akan sangat bagus untuk melihat ini digunakan oleh orang lain juga.

Inti dari pemeriksaan izin Django-guardian untuk tampilan diimplementasikan dalam fungsi get_403_or_None() . Fungsi ini memeriksa apakah pengguna memiliki semua izin yang diperlukan. https://github.com/lukaszb/django-guardian/blob/112c373f213a19d93baa81fa4a941a41333115b5/guardian/utils.py#L98

has_permissions = all(request.user.has_perm(perm, obj) for perm in perms)

Peran pendukung adalah perubahan kecil. Alih-alih memeriksa apakah pengguna memiliki izin all , kita hanya perlu memeriksa apakah pengguna memenuhi setidaknya satu izin. Sesuatu seperti

if require_all_permissions:
    has_permissions = all(request.user.has_perm(perm, obj) for perm in perms)
else:
    has_permissions = any(request.user.has_perm(perm, obj) for perm in perms)

harus melakukannya. Untuk menambahkan dukungan ini, kita hanya perlu mendefinisikan flag baru di get_403_or_None() dan pemanggilnya yang menentukan apakah kita ingin semua atau hanya beberapa izin dipenuhi.

Saya membuka #386 dan saya menyadari bahwa ini mungkin sama. Yang saya perlukan adalah bahwa dalam kode tempat saya memeriksa izin, saya dapat melakukan "apakah pengguna ini memiliki izin edit pada objek ini", tetapi ketika saya memberikan izin kepada pengguna, saya memberikan mereka izin "moderator", yang merupakan superset dari beberapa izin, termasuk izin "edit". Ini memungkinkan saya nanti untuk menambahkan lebih banyak izin ke "moderator" tanpa harus menetapkannya secara manual ke semua pengguna.

Kami dapat memberi nama hierarki izin ini, peran.

+1 untuk peran, warisan, dan opsional

Saya menerapkan konsep peran seperti di bawah ini:

sesuaikan get_40x_or_None

from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
from django.http import HttpResponseForbidden, HttpResponseNotFound
from django.shortcuts import render
from guardian.conf import settings as guardian_settings


def get_40x_or_None(request, perms, global_perms, obj=None, login_url=None,
                    redirect_field_name=None, return_403=False,
                    return_404=False):
    """check if the given perms and global_perms are both granted by the user in combination"""
    login_url = login_url or settings.LOGIN_URL
    redirect_field_name = redirect_field_name or REDIRECT_FIELD_NAME

    # Handles both original and with object provided permission check
    # as ``obj`` defaults to None

    has_permissions = False
    if not has_permissions:
        has_permissions = all(request.user.has_perm(perm, obj) for perm in perms) and \
                          all(request.user.has_perm(perm) for perm in global_perms)

    if not has_permissions:
        if return_403:
            if guardian_settings.RENDER_403:
                response = render(request, guardian_settings.TEMPLATE_403)
                response.status_code = 403
                return response
            elif guardian_settings.RAISE_403:
                raise PermissionDenied
            return HttpResponseForbidden()
        if return_404:
            if guardian_settings.RENDER_404:
                response = render(request, guardian_settings.TEMPLATE_404)
                response.status_code = 404
                return response
            elif guardian_settings.RAISE_404:
                raise ObjectDoesNotExist
            return HttpResponseNotFound()
        else:
            from django.contrib.auth.views import redirect_to_login
            return redirect_to_login(request.get_full_path(),
                                     login_url,
                                     redirect_field_name)

terapkan GlobalPermissionRequiredMixin kustom

from django.core.exceptions import PermissionDenied, ImproperlyConfigured
from guardian.mixins import PermissionRequiredMixin
from collections.abc import Iterable

from permission.utils import get_40x_or_None


class GlobalPermissionRequiredMixin(PermissionRequiredMixin):
    global_permission_required = None

    def get_global_required_permissions(self, request=None):
        """
        Returns list of permissions in format *<app_label>.<codename>* that
        should be checked against *request.user* and *object*. By default, it
        returns list from ``global_permission_required`` attribute.

        :param request: Original request.
        """
        if isinstance(self.global_permission_required, str):
            perms = [self.global_permission_required]
        elif isinstance(self.global_permission_required, Iterable):
            perms = [p for p in self.global_permission_required]
        else:
            raise ImproperlyConfigured("'GlobalPermissionRequiredMixin' requires "
                                       "'global_permission_required' attribute to be set to "
                                       "'<app_label>.<permission codename>' but is set to '%s' instead"
                                       % self.global_permission_required)
        return perms

    def check_permissions(self, request):
        """
        Checks if *request.user* has all permissions returned by
        *get_required_permissions* method.

        :param request: Original request.
        """
        obj = self.get_permission_object()

        forbidden = get_40x_or_None(request,
                                    perms=self.get_required_permissions(request),
                                    global_perms=self.get_global_required_permissions(request),
                                    obj=obj,
                                    login_url=self.login_url,
                                    redirect_field_name=self.redirect_field_name,
                                    return_403=self.return_403,
                                    return_404=self.return_404,
                                    )
        if forbidden:
            self.on_permission_check_fail(request, forbidden, obj=obj)
        if forbidden and self.raise_exception:
            raise PermissionDenied()
        return forbidden

Dalam tampilan mentah bawaan Django sekarang dimungkinkan untuk mendefinisikan global_required_permissions dan required_permissions :

class ResourceDeleteView(GlobalPermissionRequiredMixin, DeleteView):
    ...
    global_permission_required = [app.delete_resource]
    permission_required = [app.view_resource]
    ...

Kesimpulan

Solusi ini didasarkan pada bahwa User memiliki izin global untuk menghapus sumber daya, yang dapat diberikan oleh Group dari model auth Django (Peran dalam konteks masalah ini). Tetapi dia hanya dapat menghapus sumber daya karena dia memiliki objek berdasarkan view_resource Permission dari model auth Django. Saya pikir ini bisa menjadi cara umum untuk mengimplementasikan peran dengan wali Django.

Jika saya mendapatkan beberapa acungan jempol, saya akan membuka permintaan tarik dengan versi kode bebas konflik dari kode saya di atas.

Pendekatan yang sangat menarik @jokiefer. Saya suka itu, saya awalnya mencoba menerapkan guardian sepanjang garis itu. Pengguna akan memerlukan izin global view atau edit , tetapi kemudian untuk mengakses objek tertentu, izin individu untuk view atau edit diperlukan. Izin global akan meminta tindakan lebih dari izin yang memungkinkan yang tanpanya izin objek tidak masalah. Jelas itu tidak benar-benar berhasil jadi saya merestrukturisasi banyak hal.

Apakah sampel Anda memungkinkan untuk itu? yaitu global delete izin yang diperlukan, tetapi untuk benar-benar delete obyek yang berbasis obyek delete izin juga diperlukan. Berdasarkan contoh Anda, delete global diperlukan, dan kemudian objek spesifik view ? Apakah itu sedikit ketidakcocokan?

@dwasyl

Apakah sampel Anda memungkinkan untuk itu?
Ya ini akan berhasil untuk pendekatan Anda.

Tapi saya tidak fokus pada contoh di atas. Dalam proyek kami, kami menerapkan aplikasi acl sesederhana mungkin (AccessControlList). Dalam aplikasi ini ada satu model inti yang disebut acl . Model ini adalah abstraksi dari izin wali atomic . Ini menyimpan satu set pengguna, set izin, set objek yang dapat diakses. Hal ajaib di balik model ini diimplementasikan dalam beberapa sinyal. Misalnya ownable_models_handling.py adalah sinyal generik yang menambahkan sinyal dinamis ke semua model lain yang dapat diakses dengan izin wali. JIKA kita ingin mengamankan lebih banyak model, kita hanya perlu mengimplementasikan bidang m2m baru dalam model AccessControlList , yang harus dipanggil dengan accessible_MODELNAME terkemuka agar bekerja secara otomatis. Di acl_handling.py ada implementasi yang menambah/menghapus izin wali berdasarkan AccessControlList . Dengan itu kita tidak perlu memodifikasi inti wali.

Mungkin aplikasi acl ini membantu Anda lebih dari contoh di atas. Dengan beberapa pekerjaan ekstra pada aplikasi acl mungkin itu bisa di-outsource dari kode kami untuk cara umum menambahkan peran ke guadian (solusi aplikasi teratas untuk wali).

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

Allan-Nava picture Allan-Nava  ·  35Komentar

johnthagen picture johnthagen  ·  9Komentar

xuhcc picture xuhcc  ·  10Komentar

Dzejkob picture Dzejkob  ·  28Komentar

BenDevelopment picture BenDevelopment  ·  5Komentar