API SISA berbasis peran?

27

Saya sedang membangun API REST di mana beberapa pengguna dengan peran berbeda akan memiliki akses ke sumber daya yang dikandungnya.

Untuk menjaga ruang lingkup tetap sederhana, mari kita ambil domain "siswa / guru / kelas":

GET /students adalah sumber daya untuk mengakses.

Pengguna mungkin memiliki peran seperti Siswa dan / atau Guru

Siswa hanya akan memiliki akses ke siswa di kelas mereka. Guru akan memiliki akses ke siswa dari kelas yang mereka ajarkan. Beberapa kegunaan mungkin seorang siswa DAN mengajar kelas lain juga. Mereka harus memiliki akses ke siswa di kelas mereka DAN siswa di kelas yang mereka ajar.

Idealnya saya ingin menerapkan ini sebagai dua fungsi - satu per peran dan kemudian "gabungan" jika pengguna memiliki beberapa peran.

Pertanyaan saya adalah: Pola mana yang harus saya gunakan untuk mengimplementasikan ini?

Secara eksternal

  • Haruskah saya membagi API saya per peran? GET /teacher/studentsdan GET /student/studentsitu sepertinya tidak benar bagiku.
  • Simpan itu saja. Aku satu sumber daya (lebih disukai)

Secara internal

Bagaimana seharusnya diterapkan secara internal?

  • Haruskah setiap metode dimulai dengan sakelar BESAR / jika per peran?
  • Haruskah saya menerapkan repositori per peran?
  • Apakah ada pola desain yang akan membantu saya dalam mencapai ini?

Sebagai komentar sampingan: Saya menggunakan ASP.NET Web API dan Entity Framework 6 , tetapi sebenarnya tidak masalah untuk implementasi konseptual.

Casper Jensen
sumber
3
"Ini pertanyaan yang bagus, saya ingin tahu apakah Anda datang dengan solusi untuk itu, karena saya mencoba melakukan sesuatu yang serupa. Apa yang saya pikir seharusnya: Pertama, kami akan mengimplementasikan api yang mengembalikan semua data yang dibutuhkan , maka setiap klien akan terhubung tidak langsung ke api tetapi ke proxy yang akan bertanggung jawab untuk memfilter data sesuai dengan peran dari pengguna itu "
Cleiton

Jawaban:

11

Anda harus merancang API di sekitar sumber daya, bukan di sekitar peran, misalnya:

/rest/students

harus dapat diakses oleh siapa pun dengan peran yang memungkinkan mereka melihat siswa.

Secara internal, Anda menerapkan keamanan berbasis peran. Bagaimana Anda melakukannya tergantung pada rincian aplikasi Anda, tetapi katakanlah Anda memiliki tabel peran, setiap orang memiliki satu atau lebih peran, dan peran itu menentukan apa yang dapat diakses setiap orang. Anda telah menyatakan aturan untuk mengakses siswa:

  • siswa dapat mengakses siswa di kelas yang mereka ambil
  • guru dapat mengakses siswa di kelas yang mereka ajar

Jadi ketika seseorang memanggil:

/rest/students

Anda memanggil metode yang mengakses siswa, lewat peran orang tersebut. Berikut ini beberapa kode semu:

roles = person.roles; //array
students = getStudents( roles );
return students;

dan dalam metode itu, Anda bisa mendapatkan siswa untuk setiap peran dengan panggilan terpisah, misalnya:

factory = getFactory();
classes= [];
students = [];
for( role in roles ){
    service = factory.getService( role );
    // implementation details of how you get classes for student/teacher are hidden in the service
    classes = classes.merge( service.getClasses( person ) );
    // classes[] has class.students[]
    // loop on classes and add each student to students, or send back classes with nested students? depends on use case
  }
}

Itu ide yang sangat kasar untuk apa yang bisa Anda lakukan dan tidak harus sesuai dengan kebutuhan spesifik Anda, tetapi itu harus memberi Anda rasa dari potongan yang terlibat. Jika Anda ingin mengembalikan kelas dengan masing-masing siswa terdaftar, ini adalah pendekatan yang baik. Jika Anda hanya menginginkan siswa, Anda dapat mengekstraksi mereka dari setiap kelas dan menggabungkannya ke dalam koleksi siswa.

Tidak, Anda tidak boleh memiliki repositori terpisah per peran. Semua peran yang dilakukan adalah menentukan bagaimana Anda mendapatkan data, dan mungkin apa yang dapat Anda lakukan dengan data tersebut (mis. Guru dapat memasuki nilai siswa). Data itu sendiri sama.

Adapun pola, pendekatan ini menggunakan Pola Pabrik untuk mengabstraksi layanan yang mendapatkan data berdasarkan peran. Mungkin perlu atau tidak pantas untuk memiliki layanan terpisah berdasarkan peran. Saya suka pendekatan ini karena meminimalkan jumlah kode pada setiap tahap program dan membuatnya lebih mudah dibaca daripada switch atau jika blok.

Robert Munn
sumber
1
Terima kasih balasannya. Saya akhirnya melakukan sesuatu seperti yang Anda sarankan. Dengan menggunakan LINQ2SQL (C #) saya bisa meneruskan permintaan untuk setiap "peran" dan menerapkan di mana untuk setiap peran yang didapat pengguna. Hasilnya adalah pernyataan sql dengan kondisi "ATAU" untuk setiap peran yang dapat diakses pengguna. Jika tidak ada peran yang ditetapkan untuk pengguna maka saya cukup mengembalikan Enumarable.Empty () si pemanggil.
Casper Jensen
0

Temukan pena dan kertas dan mulai memodelkan sistem Anda.

Anda akan menemukan bahwa Anda mungkin memerlukan entitas domain yang disebut PERSON. Karena MAHASISWA dan GURU "adalah-" ORANG, Anda dapat membuat entitas abstrak yang disebut PERSON dengan atribut generik seperti nama depan, nama belakang, dll. GURU -> adalah-a -> Orang. Sekarang Anda dapat mencoba menemukan karakteristik untuk GURU yang tidak berlaku untuk SISWA; mis. GURU mengajar CLASS tentang satu atau lebih SUBYEK.

Menegakkan keamanan dianggap sebagai aspek non-fungsional dari aplikasi Anda. Ini adalah masalah lintas sektoral yang harus ditangani di luar "logika bisnis" Anda. Seperti yang ditunjukkan oleh @Robert Munn, PERAN harus dijaga di satu tempat. Menggunakan peran untuk membatasi akses ke fungsi tertentu agak kasar, dan konsep ini disebut kontrol akses berbasis peran (RBAC).

Untuk memverifikasi apakah seorang guru harus diizinkan melihat nilai siswa, harus dinyatakan dalam model domain Anda. Katakanlah seorang guru memiliki kelas pada pemrograman mata pelajaran. Anda mungkin akan mengekspresikan dalam model Anda bahwa siswa menghadiri kelas untuk mata pelajaran yang berbeda. Di sinilah logika aplikasi / bisnis masuk. Ini adalah logika yang dapat Anda verifikasi menggunakan pengembangan yang digerakkan oleh tes.

Anda harus membagi sumber daya Anda untuk membuat aplikasi Anda dapat diuji dan modular.

Bagaimanapun, cara terbaik untuk benar-benar menunjukkan apa yang saya maksud adalah dengan menunjukkannya dengan kode :) Ini adalah halaman GitHub: https://github.com/thomasandersen77/role-based-rest-api

Semoga berhasil :)

Thomas Andersen
sumber
3
tautan Anda telah hilang ...
Cleiton