Saya sedang mengerjakan aplikasi Django yang besar, yang sebagian besar membutuhkan login untuk mengakses. Ini berarti bahwa di seluruh aplikasi kami, kami telah menaburkan:
@login_required
def view(...):
Tidak apa-apa, dan berfungsi dengan baik selama kita ingat untuk menambahkannya di mana-mana ! Sayangnya terkadang kita lupa, dan kegagalan seringkali tidak terlalu terbukti. Jika satu-satunya tautan ke tampilan ada di laman @login_required maka Anda tidak akan menyadari bahwa Anda benar-benar dapat mencapai tampilan itu tanpa masuk. Tetapi orang jahat mungkin memperhatikan, yang merupakan masalah.
Ide saya adalah membalikkan sistem. Alih-alih harus mengetik @login_required di mana-mana, saya malah memiliki sesuatu seperti:
@public
def public_view(...):
Hanya untuk urusan umum. Saya mencoba menerapkan ini dengan beberapa middleware dan saya tidak bisa membuatnya bekerja. Semua yang saya coba berinteraksi buruk dengan middleware lain yang kami gunakan, saya kira. Selanjutnya saya mencoba menulis sesuatu untuk menelusuri pola URL untuk memeriksa bahwa semua yang bukan @public telah ditandai @login_required - setidaknya kita akan mendapatkan kesalahan cepat jika kita lupa sesuatu. Tapi kemudian saya tidak tahu bagaimana cara mengetahui apakah @login_required telah diterapkan ke tampilan ...
Jadi, apa cara yang benar untuk melakukan ini? Terima kasih untuk bantuannya!
Jawaban:
Middleware mungkin merupakan pilihan terbaik Anda. Saya telah menggunakan potongan kode ini sebelumnya, dimodifikasi dari cuplikan yang ditemukan di tempat lain:
Kemudian di settings.py, daftarkan URL dasar yang ingin Anda lindungi:
Selama situs Anda mengikuti konvensi URL untuk halaman yang memerlukan autentikasi, model ini akan berfungsi. Jika ini bukan kesesuaian one-to-one, Anda dapat memilih untuk memodifikasi middleware agar lebih sesuai dengan keadaan Anda.
Apa yang saya suka tentang pendekatan ini - selain menghilangkan kebutuhan untuk mengotori basis kode dengan
@login_required
dekorator - adalah bahwa jika skema otentikasi berubah, Anda memiliki satu tempat untuk pergi untuk membuat perubahan global.sumber
@public
dekorator, yang menyetel_public
atribut pada tampilan, dan middleware kemudian melewatkan tampilan tersebut. Dekorator csrf_exempt Django bekerja dengan cara yang samaAda alternatif untuk menempatkan dekorator pada setiap fungsi tampilan. Anda juga bisa meletakkan
login_required()
dekorator diurls.py
file. Meskipun ini masih merupakan tugas manual, setidaknya Anda memiliki semuanya di satu tempat, yang memudahkan untuk mengaudit.misalnya,
Perhatikan bahwa fungsi tampilan diberi nama dan diimpor secara langsung, bukan sebagai string.
Perhatikan juga bahwa ini berfungsi dengan objek tampilan yang dapat dipanggil, termasuk kelas.
sumber
Dalam Django 2.1, kita dapat menghias semua metode dalam kelas dengan:
UPDATE: Saya juga menemukan yang berikut ini berfungsi:
dan setel
LOGIN_URL = '/accounts/login/'
di settings.py Andasumber
Sulit untuk mengubah asumsi built-in dalam Django tanpa mengerjakan ulang cara url diserahkan untuk melihat fungsi.
Daripada menyia-nyiakan tentang internal Django, berikut ini audit yang dapat Anda gunakan. Cukup periksa setiap fungsi tampilan.
Jalankan ini dan periksa keluaran untuk
def
s tanpa dekorator yang sesuai.sumber
Berikut adalah solusi middleware untuk django 1.10+
Middleware di harus ditulis dengan cara baru di django 1.10+ .
Kode
Instalasi
Tambahkan ke MIDDLEWARE
MIDDLEWARE = [... '.middleware.RequireLoginMiddleware', # Membutuhkan login]
Sumber:
Jawaban ini oleh Daniel Naab
Tutorial Django Middleware oleh Max Goodridge
Django Middleware Docs
sumber
__call__
,process_view
pengait tersebut masih digunakan [diedit]Terinspirasi oleh jawaban Ber, saya menulis potongan kecil yang menggantikan
patterns
fungsi tersebut, dengan membungkus semua panggilan balik URL denganlogin_required
dekorator. Ini bekerja di Django 1.6.Menggunakannya bekerja seperti ini (panggilan ke
list
diperlukan karenayield
).sumber
Anda tidak bisa memenangkan ini. Anda hanya perlu membuat pernyataan tentang persyaratan otorisasi. Di mana lagi Anda akan meletakkan deklarasi ini kecuali right by view function?
Pertimbangkan untuk mengganti fungsi tampilan Anda dengan objek yang dapat dipanggil.
Anda kemudian membuat subkelas dari fungsi tampilan
LoginViewFunction
.Itu tidak menyimpan baris kode apa pun. Dan itu tidak membantu masalah "kita lupa". Yang dapat Anda lakukan hanyalah memeriksa kode untuk memastikan bahwa fungsi tampilan adalah objek. Dari kelas yang tepat.
Namun meskipun demikian, Anda tidak akan pernah benar-benar tahu bahwa setiap fungsi tampilan sudah benar tanpa rangkaian pengujian unit.
sumber
def
. Anda dapat dengan mudah menulis skrip yang sangat pendek untuk memindai semua yang adadef
di semua modul tampilan dan menentukan apakah @login_required dilupakan.urls.py
.Mungkinkah memiliki satu titik awal untuk semua
urls
dalam semacam penyertaan dan yang menghiasinya menggunakan paket ini https://github.com/vorujack/decorate_url .sumber
Ada aplikasi yang menyediakan solusi plug-and-play untuk ini:
https://github.com/mgrouchy/django-stronghold
sumber