Menerapkan DDD: pengguna dan izin

16

Saya sedang mengerjakan aplikasi kecil yang mencoba memahami prinsip-prinsip desain berbasis domain. Jika berhasil, ini mungkin menjadi pilot untuk proyek yang lebih besar. Saya mencoba mengikuti buku "Menerapkan Desain Berbasis Domain" (oleh Vaughn Vernon) dan mencoba menerapkan forum diskusi yang serupa dan sederhana. Saya juga sudah memeriksa sampel IDDD di github. Saya mengalami beberapa kesulitan dalam mengadopsi Identitas dan Akses ke kasus saya. Biarkan saya memberikan beberapa informasi latar belakang:

  • Saya (semoga) memahami alasan di balik pemisahan antara pengguna dan logika izin: ini adalah domain pendukung, dan ini merupakan konteks terikat yang berbeda.
  • Dalam domain inti, tidak ada pengguna, hanya Penulis, Moderator, dll. Ini dibuat dengan menjangkau konteks Identitas dan Akses menggunakan layanan dan kemudian menerjemahkan objek Pengguna yang diterima ke dan Moderator.
  • Operasi domain dipanggil dengan peran terkait sebagai parameter: misalnya:

    ModeratePost( ..., moderator);

  • Metode objek domain memeriksa jika turunan Moderator yang diberikan bukan nol (turunan Moderator akan menjadi nol jika pengguna bertanya dari konteks Identity and Access tidak memiliki peran Moderator).

  • Dalam satu kasus, ia melakukan pemeriksaan tambahan sebelum mengubah sebuah Posting:

    if (forum.IsModeratedby(moderator))

Pertanyaan saya adalah:

  • Dalam kasus terakhir, bukankah masalah keamanan dicampur lagi ke dalam domain inti? Sebelumnya buku-buku menyatakan "dengan siapa yang dapat memposting subjek, atau dalam kondisi apa yang diizinkan. Forum hanya perlu tahu bahwa seorang Penulis melakukan itu sekarang".

  • Implementasi berbasis peran dalam buku ini cukup mudah: ketika seorang Moderator adalah domain inti mencoba untuk mengubah userId saat ini menjadi instance Moderator atau menjadi seorang Penulis ketika diperlukan. Layanan akan merespons dengan contoh yang sesuai atau nol jika pengguna tidak memiliki peran yang diperlukan. Namun, saya tidak bisa melihat bagaimana saya bisa mengadaptasi ini ke model keamanan yang lebih kompleks; proyek kami saat ini yang saya uji coba memiliki model yang agak rumit dengan grup, ACL, dll.

Bahkan dengan aturan yang tidak terlalu rumit, seperti: "Sebuah posting harus diedit hanya oleh Pemilik atau Editornya", pendekatan ini tampaknya rusak, atau setidaknya saya tidak melihat cara yang benar untuk mengimplementasikannya.

Dengan menanyakan konteks Identitas dan Akses untuk instance OwnerOrEditor tidak terasa benar, dan saya akan berakhir dengan semakin banyak kelas terkait keamanan di domain inti. Selain itu, saya harus lulus tidak hanya userId, tetapi pengidentifikasi sumber daya yang dilindungi (id posting, forum, dll.) Ke konteks keamanan, yang mungkin seharusnya tidak peduli tentang hal-hal ini (apakah benar? )

Dengan menarik izin ke domain inti dan memeriksanya dalam metode objek domain atau dalam layanan, saya akan berakhir di titik awal: mencampur masalah keamanan dengan domain.

Saya sudah membaca di suatu tempat (dan saya cenderung setuju dengan itu) bahwa hal-hal yang terkait dengan izin ini seharusnya tidak menjadi bagian dari domain inti, kecuali keamanan dan izin adalah domain inti itu sendiri. Apakah aturan sederhana seperti yang diberikan di atas membenarkan menjadikan keamanan sebagai bagian dari domain inti?

Pilgrim Little
sumber
Mungkin Anda dapat menemukan apa yang Anda butuhkan di sini: stackoverflow.com/a/23485141/329660 Juga, hanya karena konteks Kontrol Akses tahu tentang ID sumber daya tidak berarti memiliki pengetahuan domain tentang jenis entitas yang sumber daya itu atau apa itu tidak.
guillaume31
Terima kasih, saya telah melihat posting itu sebelumnya, masalah saya persis seperti yang dikatakan oleh edit pada akhirnya: Saya ingin memindahkan kontrol akses keluar dari domain inti saya tetapi saya merasa saya telah membentur dinding dengan implementasi saya. Namun, saran Anda tentang ID sumber daya masuk akal: karena saya tidak menggunakan konsep Pengguna atau Peran dalam domain inti tetapi peran konkret, mungkin saya bisa menggunakan konsep Sumber Daya di BC keamanan dan memetakannya ke beton terkait konsep domain. Patut dicoba, terima kasih!
LittlePilgrim
Jangan sampel kode dalam tautan setidaknya menjawab "Saya tidak bisa melihat bagaimana saya bisa mengadaptasi ini ke model keamanan yang lebih kompleks" ?
guillaume31
Masalah saya bukan dengan implementasi model keamanan itu sendiri, saya tidak bisa melihat bagaimana saya harus memetakan aturan yang lebih rumit ini ke dalam domain. Bagaimana seharusnya Pengguna -> pemetaan pemetaan berubah jika itu bukan model peran sederhana di sisi keamanan? Melewati ID sumber daya ke konteks lain mungkin bekerja, seperti HasPermissionToEdit(userId, resourceId)tapi saya merasa tidak benar untuk mencemari logika domain dengan panggilan ini. Mungkin saya harus memeriksa ini dalam metode layanan aplikasi, sebelum memohon logika domain?
LittlePilgrim
Tentu saja harus dalam layanan aplikasi ... Saya pikir itu jelas dari bagian kode seperti UserService @AccessControlList[inf3rno]pada jawaban yang saya tautkan.
guillaume31

Jawaban:

6

Terkadang sulit untuk membedakan antara aturan kontrol akses nyata dan invarian domain yang membatasi kontrol akses.

Khususnya, aturan yang bergantung pada data yang hanya tersedia jauh dalam perjalanan sepotong logika domain tertentu mungkin tidak mudah diekstraksi dari domain. Biasanya, Access Control dipanggil sebelum atau setelah operasi domain dilakukan tetapi tidak selama.

assert (forum.IsModeratedBy(moderator))Contoh Vaughn Vernon mungkin seharusnya di luar Domain, tetapi itu tidak selalu layak.

Saya perlu melewati tidak hanya userId, tetapi pengidentifikasi sumber daya yang dilindungi (id posting, forum, dll.) Ke konteks keamanan, yang mungkin tidak peduli tentang hal-hal ini (apakah benar?)

Jika ada BC Keamanan dan Anda ingin menangani logika itu, tidak perlu tahu apa itu Forum secara detail, tetapi:

  • Itu hanya bisa memiliki pengetahuan tentang konsep-konsep seperti "dimoderasi oleh" dan memberikan atau menolak hak akses yang sesuai.
  • Anda bisa memiliki logika adaptor yang berlangganan acara Core Domain dan menerjemahkannya ke pasangan nilai kunci sederhana (sumber daya, yang berwenang) untuk Keamanan BC untuk disimpan dan digunakan.
guillaume31
sumber
Karena kedua jawaban itu bermanfaat dan lebih atau kurang menunjuk ke arah yang sama, saya telah memutus keduanya. Saya menerima yang ini, karena @ guillaume31 memiliki lebih atau kurang menjawab pertanyaan saya tentang implementasi Vernon dan saya akan melanjutkan implementasi saya berdasarkan petunjuknya tentang menggunakan sumber daya di BC Keamanan.
LittlePilgrim
Saya harus mengatakan saya pikir ini berlawanan dengan jawaban saya.
Ewan
1
Mungkin saya terlalu bingung sekarang, tetapi interpretasi saya (untuk kedua jawaban): 1. Jauhkan masalah keamanan dari domain dan gunakan BC keamanan sebagai layanan 2. Panggil layanan sebelum memanggil objek domain apa pun 3. Layanan akan melakukan pemetaan dari pengguna / acl ke moderator, penulis, dll. moderator = securityService.GetModerator(userId, forumId) 4. Logika domain akan diimplementasikan pada objek-objek ini seperti pada moderator.EditPost () 5. Metode seperti EditPost tidak akan tahu apa-apa tentang konsep keamanan, tidak akan ada pemeriksaan tambahan di sana
LittlePilgrim
Saya masih mencari jawaban / arahan untuk hal ini sendiri, tetapi saya telah menemukan bahwa logika otorisasi apa pun yang bergantung pada keadaan objek saat ini (seperti jika saat ini ditugaskan ke moderator) sebenarnya adalah logika bisnis yang termasuk dalam domain Anda dan lebih lanjut bahwa jika tidak ada dalam domain Anda, Anda berisiko berakhir dalam keadaan tidak valid jika model dapat diperbarui secara bersamaan. Misalnya jika Anda memvalidasi kepemilikan menggunakan kebijakan dan kemudian pergi untuk memperbarui objek itu - di banyak domain, kepemilikan dapat berubah dan tindakan mungkin tidak lagi valid.
Jordan
Kecuali jika Anda memiliki konteks kolaboratif yang sangat kompleks, Anda mungkin dapat menerapkan model konkurensi optimis di sini menggunakan versi, tetapi jika cek Anda tidak dilakukan di dalam atau setidaknya terhadap contoh agregat tertentu maka cek Anda mungkin gagal konsisten dengan yang sebenarnya keadaan objek pada saat Anda bertahan perubahan Anda.
Jordan
5

Otentikasi dan Otorisasi adalah contoh buruk untuk DDD.

Tidak satu pun dari hal-hal ini yang merupakan bagian dari suatu Domain kecuali perusahaan Anda menciptakan produk keamanan.

Persyaratan Bisnis atau domain adalah, atau seharusnya, "Saya memerlukan otentikasi berbasis peran"

Anda kemudian memeriksa peran sebelum memanggil fungsi domain.

Di mana Anda memiliki persyaratan kompleks seperti 'Saya dapat mengedit posting saya sendiri tetapi tidak orang lain' memastikan bahwa domain Anda memisahkan fungsi edit EditOwnPost()dan EditOthersPost()sehingga Anda memiliki fungsi sederhana untuk pemetaan peran

Anda juga dapat memisahkan fungsionalitas menjadi Objek Domain, seperti Poster.EditPost()dan Moderator.EditPost()ini adalah pendekatan yang lebih OOP, meskipun pilihan Anda mungkin tergantung pada apakah metode Anda dalam Layanan Domain atau Objek Domain.

Namun Anda memilih untuk memisahkan kode, pemetaan Peran akan terjadi di luar Domain. jadi misalnya jika Anda memiliki pengontrol webapi:

PostController : ApiController
{
    [Authorize(Roles = "User")]
    public void EditOwnPost(string postId, string newContent)
    {
        this.postDomainService.EditOwnPost(postId, string newContent);
    }

    [Authorize(Roles = "Moderator")]
    public void EditOtherPost(string postId, string newContent)
    {
        this.postDomainService.EditOtherPost(postId, string newContent);
    }
}

Seperti yang Anda lihat meskipun pemetaan peran dilakukan pada lapisan hosting, logika kompleks dari apa yang merupakan pengeditan posting Anda sendiri atau orang lain adalah bagian dari domain.

Domain mengakui perbedaan tindakan, tetapi persyaratan keamanan hanyalah bahwa "fungsi dapat dibatasi oleh peran" .

Ini mungkin lebih jelas dengan pemisahan objek domain, tetapi pada dasarnya Anda memeriksa metode yang membangun objek, bukan metode yang memanggil metode layanan. Persyaratan Anda, jika Anda masih ingin menyuarakannya sebagai bagian dari domain akan menjadi 'hanya moderator yang dapat membangun objek moderator'

Ewan
sumber
4
Memeriksa peran "secara statis" sedikit disederhanakan. Bagaimana jika seorang moderator tidak diperbolehkan mengedit posting dari moderator lain? Bukankah seharusnya cek ini menjadi bagian dari domain?
Réda Housni Alaoui
2
@ RédaHousniAlaoui Saya bertanya-tanya tentang ini juga. Saya tidak bisa memikirkan cara untuk menangani ini selain dari memasukkan beberapa menyebutkan Pengguna / Moderator dalam domain, atau melakukan semacam logika di dalam ApiController untuk mendapatkan peran penulis posting. Tak satu pun dari ini tampaknya benar, dan ini adalah hal yang cukup umum dalam pengalaman saya bahwa beberapa panduan yang jelas akan sangat membantu.
Jimmy
1
@ Erwan, use case yang saya bicarakan ini dinamis. Mendasarkan kalimat "Otentikasi dan Otorisasi adalah contoh buruk untuk DDD" pada contoh hello world adalah tidak jujur. DDD ada di sini untuk menghindari kompleksitas yang tidak disengaja dan memungkinkan untuk mengelola kompleksitas domain. Izin dinamis bukanlah kompleksitas yang tidak disengaja atau sesuatu yang tidak terjadi dalam kehidupan nyata.
Réda Housni Alaoui
1
IMHO, masalah dengan solusi Anda adalah bahwa itu tidak memuaskan pelanggan. Pelanggan sering ingin dapat mengubah hubungan itu secara dinamis. Selain itu, itulah yang terjadi ketika vendor menyediakan perangkat lunak perusahaan yang sama untuk perusahaan yang berbeda. Jika perangkat lunaknya tidak bisa di-tweak, vendor akhirnya akan mati.
Réda Housni Alaoui
1
"Tapi itu umumnya diakui sebagai" hal buruk "pengaturan keamanan Anda menjadi tidak terkelola dari waktu ke waktu yang secara efektif berarti aplikasi Anda menjadi tidak aman." Dengan desain dan pengujian yang benar, ini benar-benar dapat dikelola. Tapi, dari XP saya, untuk menghasilkan desain yang benar, domain harus memeriksa izin. Alternatifnya adalah utopia.
Réda Housni Alaoui