Di mana pemeriksaan izin pengguna harus dilakukan di dan MVC dan oleh siapa?

26

Haruskah pemeriksaan izin pengguna dilakukan dalam model atau pengontrol? Dan siapa yang harus menangani pemeriksaan izin, objek Pengguna atau pembantu UserManagement?

Di mana itu harus terjadi?

Memeriksa di Controller:

class MyController {
  void performSomeAction() {
    if (user.hasRightPermissions()) {
      model.someAction();
    }
  }
  ...

Memiliki pemeriksaan di Kontroler membantu membuat Model tindakan sederhana, sehingga kami dapat menyimpan semua logika untuk Pengendali.

Memeriksa dalam Model:

class MyModel {
  void someAction() {
    if (user.hasRightPermissions()) {
      ...
    }
  }
  ...

Dengan meletakkan cek di Model, kami menyulitkan Model, tetapi juga memastikan kami tidak sengaja membiarkan pengguna melakukan hal-hal yang seharusnya tidak dilakukan di Controller.

Dan oleh siapa?

Setelah kami menetap di tempat itu, siapa yang harus melakukan cek? Pengguna?

Class User {
  bool hasPermissions(int permissionMask) {
    ...
  }
  ...

Tetapi sebenarnya bukan tanggung jawab pengguna untuk mengetahui apa yang dapat dia akses, jadi mungkin beberapa kelas pembantu?

Class UserManagement {
  bool hasPermissions(User user, int permissionMask) {
    ...
  }
  ...

Saya tahu itu biasa untuk mengajukan satu pertanyaan saja, tapi pertanyaan, tapi saya pikir ini bisa dijawab dengan baik bersama-sama.

kba
sumber

Jawaban:

20

Seperti biasa, "itu tergantung"

  • cek izin fungsional akan bekerja di mana saja itu lebih mudah untuk menempatkan mereka,
  • tetapi jika Anda mengajukan pertanyaan teknis maka jawabannya mungkin 'taruh cek di objek yang memiliki data yang diperlukan untuk melakukan pemeriksaan' (yang mungkin controller).
  • tetapi jika Anda mengajukan pertanyaan filosofis, saya menyarankan jawaban alternatif: jangan perlihatkan tindakan pengguna yang tidak diizinkan mereka lakukan .

Jadi dalam kasus terakhir Anda mungkin memiliki izin memeriksa di controller diimplementasikan sebagai properti boolean, dan mengikat properti itu ke properti Terlihat dari tombol atau panel di antarmuka pengguna yang mengontrol tindakan

sebagai pengguna, frustasi melihat tombol untuk tindakan yang tidak dapat saya lakukan; terasa seperti saya tidak diajak bersenang-senang;)

Steven A. Lowe
sumber
Aplikasi kami mengimplementasikan skenario ketiga dengan pengecualian bahwa kami tidak menyembunyikan kontrol, kami menonaktifkannya. Sayangnya semuanya dilakukan di Winforms code-behind, jadi tidak benar-benar relevan dengan pertanyaan OP.
Dave Nay
11
"Mengecewakan melihat tombol untuk tindakan yang tidak dapat saya lakukan" -> Cobalah untuk mengunggah posting Anda sendiri :)
Rowan Freeman
5
Tidak cukup hanya dengan menyembunyikan tombol untuk tindakan yang tidak dapat dilakukan oleh pengguna, server harus memeriksa setiap permintaan untuk izin. Butir ketiga bukanlah "jawaban alternatif", itu adalah sesuatu yang harus dilakukan selain memeriksa izin sisi server.
Flimm
@Flimm setuju, jika permintaan ditangani oleh server; pertanyaan spesifiknya adalah tentang kelas Controller
Steven A. Lowe
7

Keamanan adalah masalah lintas sektoral, oleh karena itu perlu diimplementasikan dalam berbagai lapisan. Berikut ini adalah contoh untuk MVC tetapi konsep ini berlaku untuk arsitektur dan / atau pola lain, Anda hanya perlu mengidentifikasi poin-poin penegakan.

Di mana itu harus terjadi?

Tampilan mungkin mengandung elemen UI (widget, tombol, menu, dll.) Yang perlu ditampilkan atau tidak untuk beberapa pengguna, berdasarkan izin mereka. Ini bisa menjadi tanggung jawab view engine , karena Anda tidak ingin setiap view menangani ini sendiri. Tergantung pada jenis elemen yang Anda lakukan otorisasi pada Anda, pindahkan tanggung jawab ini di tempat lain. Sebagai contoh, pikirkan sebuah menu di mana beberapa item harus ditampilkan dan beberapa tidak. Item dapat diimplementasikan sebagai daftar di suatu tempat dan memfilter daftar itu berdasarkan izin lalu meneruskannya ke tampilan.

Pengendali merespons permintaan, jadi jika pengguna tidak memiliki izin untuk melakukan suatu tindakan, ia harus diperiksa sebelum tindakan tersebut dipanggil, memindahkan tanggung jawab ke tindakan yang dilakukan oleh penyerang alih-alih menyimpannya di dalam pengontrol. Ini memiliki keuntungan menjaga pengontrol Anda tetap bersih dan jika ada perubahan pada izin Anda tidak perlu menyaring pengontrol Anda untuk menerapkan perubahan tersebut.

Sumber daya ditampilkan berdasarkan izin. Ini biasanya dilakukan di tingkat basis data , karena Anda tidak ingin menarik semuanya dari basis data dan kemudian menerapkan izin.

Seperti yang Anda lihat, tergantung pada apa yang ingin Anda otorisasi ada beberapa tempat di mana hal ini harus dilakukan. Tujuannya adalah untuk tidak mengganggu mungkin, sehingga ketika kebijakan keamanan Anda berubah, Anda dapat dengan mudah menerapkannya, lebih disukai tanpa mengubah kode aplikasi Anda. Ini mungkin tidak berlaku untuk aplikasi kecil, di mana set izinnya cukup kecil dan tidak terlalu sering berubah. Dalam aplikasi perusahaan, ceritanya sangat berbeda.

Siapa yang harus melakukannya?

Jelas bukan modelnya. Setiap lapisan harus memiliki titik penegakan yang menangani otorisasi. Teks miring di atas menyoroti kemungkinan titik penegakan untuk setiap level.

Lihatlah XACML . Anda tidak harus mengimplementasikannya apa adanya, tetapi itu akan memberi Anda beberapa arahan yang bisa Anda ikuti.

devnull
sumber
Ini jawaban terbaik. Untuk beberapa alasan, yang teratas dan yang lainnya berurusan dengan perbedaan antara pengontrol dan tampilan, atau tampilan dan model, yang bukan yang diminta OP. Terima kasih!
redFur
1

Saya menggunakan skema berikut. Layak untuk dikatakan bahwa sebagian besar pemeriksaan izin pengguna dapat dibagi menjadi dua kasus umum:

  • akses pengguna ke tindakan pengontrol berdasarkan peran pengguna tanpa memeriksa parameter tindakan dipanggil dengan,
  • akses pengguna ke model berdasarkan pada logika atau hubungan antara pengguna tertentu dan model tertentu.

Akses ke tindakan pengontrol tanpa memeriksa atribut biasanya diimplementasikan dalam kerangka kerja MVC. Ini sederhana sekali: Anda menetapkan aturan, pengguna Anda memiliki peran. Anda cukup memeriksa bahwa pengguna memiliki izin untuk mencari perannya dalam aturan.

Akses pengguna ke model tertentu harus didefinisikan dalam model. (Aktor adalah kelas pengguna dasar. Misalkan dapat berupa pelanggan, penjual, atau tamu.)

interface ICheckAccess
{
    public function checkAccess(Actor $actor, $role);
}

class SomeModel implements ICheckAccess
{
    public function checkAccess(Actor $actor, $role)
    {
        // Your permissions logic can be as sophisticated as you want.
    }
}

Menempatkan logika itu dalam model mendatangkan untung. Metode pemeriksaan akses dapat diwariskan, Anda tidak perlu membuat kelas tambahan, Anda dapat menggunakan keunggulan OOP umum.

Selanjutnya, untuk menyederhanakan pemeriksaan akses, kami mengambil beberapa asumsi yang hampir selalu diterapkan untuk kesederhanaan dan gaya yang baik:

  • biasanya kontroler terkait dengan beberapa kelas model;
  • tindakan yang diperiksa untuk akses mengambil id model tunggal sebagai parameter;
  • parameter ini selalu dapat diakses secara seragam dari metode kelas pengendali basis;
  • action ditempatkan di controller sesuai dengan model yang diambil id action.

Dengan asumsi ini, tindakan yang menggunakan id model dapat dikaitkan dengan instance model tertentu. Bahkan, sebagian besar tindakan dapat dengan mudah diubah dan dipindahkan agar sesuai dengan asumsi yang disebutkan di atas.

Kemudian, beberapa kelas pengontrol abstrak dasar harus didefinisikan dan diwarisi.

abstract class ModelController
{
    // Retrieve model from database using id from action parameter.
    public abstract function loadModel($id);

    // Returns rules for user role to pass to SomeModel::checkAccess()
    // Something like array('view' => 'viewer', 'delete' => 'owner', 'update' => 'owner')
    public abstract function modelRules();

    public abstract fucntion getIdParameter();

    public function filterModelAccess()
    {
        $id = $this->getIdParameter();
        if(!$this->checkModelAccess($id))
            throw new HttpException(403);
    }

    public function checkModelAccess($id)
    {
        $model = $this->loadModel($id);
        $actor = My::app()->getActor();
        $rules = $this->modelRules();
        $role = $rules[My::app()->getActionName()];
        return $model->chechAccess($actor, $role);
    }
}

Anda dapat memanggil metode SomeController :: checkModelAccess ($ id) ketika Anda membuat menu dan memutuskan apakah akan menampilkan beberapa tautan.

George Sovetov
sumber
Saya minta maaf untuk PHP.
George Sovetov
1

Baik dalam Model dan Lihat

Dalam Tampilan - karena UI tidak boleh menampilkan elemen-UI yang dibatasi untuk pengguna saat ini

(seperti, katakanlah, tombol "Hapus" harus ditampilkan kepada orang-orang dengan izin yang sesuai)

Dalam Model - karena aplikasi Anda mungkin memiliki semacam API, bukan? API juga harus memeriksa izin dan mungkin menggunakan kembali Model.

(seperti, katakanlah, Anda memiliki tombol "Hapus" di UI dan metode API "http: / server / API / DeleteEntry / 123" pada saat yang sama

jitbit
sumber
Mengapa Anda memilih model daripada controller?
Flimm
tidak yakin mengapa tampilan, model, dan tidak di controller, di mana sebagian besar waktu itu dilakukan.
Wakil Presiden
@VP controller tidak memiliki kekuatan untuk menampilkan / menyembunyikan elemen UI (selain melewati bool-var TO THE VIEW)
jitbit
Saya tidak tahu, di mana-mana biasanya dilakukan di lapisan controller, itu sebabnya saya penasaran.
Wakil Presiden
0

MVC adalah pola presentasi. Karena pandangan dan pengontrol seperti itu seharusnya hanya memiliki tanggung jawab mengenai presentasi. Beberapa izin berlaku untuk presentasi, seperti mode ahli, fitur UI eksperimental atau desain yang berbeda. Itu bisa ditangani oleh MVC-controller.

Banyak jenis izin lainnya yang relevan pada beberapa lapisan aplikasi. Misalnya jika Anda ingin memiliki pengguna yang hanya dapat melihat data dan tidak mengubah hal-hal:

  • lapisan presentasi harus menyembunyikan fitur pengeditan
  • Jika fitur pengeditan dipanggil, ini dapat / harus dideteksi (oleh aplikasi bagian khusus dari lapisan bisnis, bukan bagian spesifik domain dari itu - TrainEditor, bukan Train) dan mungkin menyebabkan pengecualian
  • Lapisan akses data juga dapat memeriksa penulisan, tetapi untuk jenis perizinan yang lebih kompleks yang dengan cepat memerlukan terlalu banyak pengetahuan tentang lapisan bisnis menjadi ide yang bagus.

Ada beberapa duplikasi dalam pendekatan ini. Tetapi karena presentasi biasanya tidak stabil, orang dapat membuat kasus yang bagus untuk memeriksa izin di bagian aplikasi yang biasanya lebih stabil, bahkan jika itu berarti beberapa pemeriksaan berlebihan jika lapisan presentasi berfungsi sebagaimana dimaksud.

Patrick
sumber