API REST на основі ролі?


27

Я будую API REST, для якого кілька користувачів з різними ролями матимуть доступ до ресурсів, які він містить.

Щоб просто не було простору, візьмемо домен "студент / викладач / клас":

GET /students є ресурсом для доступу.

Користувачі можуть мати такі ролі, як Студент та / або Вчитель

Студенти матимуть доступ лише до учнів своїх класів. Вчителі матимуть доступ до учнів класів, які вони викладають. Деякі користування можуть бути студентами, а також навчати інших класів. Вони повинні мати доступ до учнів своїх класів І до учнів класів, які вони викладають.

В ідеалі я хочу реалізувати це як дві функції - по одній на роль, а потім "об'єднати", якщо у користувача є кілька ролей.

Моє запитання: Яку модель слід використовувати для здійснення цього?

Зовнішньо

  • Чи слід розділити API на роль? GET /teacher/studentsі GET /student/studentsмені це не здається правильним.
  • Зберігайте все, що я один ресурс (бажано)

Внутрішньо

Як це потрібно впровадити внутрішньо?

  • Чи повинен кожен метод починатися з великого перемикача / якщо на роль?
  • Чи потрібно реалізовувати сховище на роль?
  • Чи є модель дизайну, яка допоможе мені досягти цього?

В якості побічного коментаря: я використовую веб-API ASP.NET та Entity Framework 6 , але це не має значення для концептуальної реалізації.


3
"Це чудове запитання. Я хотів би знати, чи ви вирішили це зробити, тому що я намагаюся зробити щось подібне. Я думаю, що це має бути: По-перше, ми реалізуємо api, який повертає всі необхідні дані , тоді кожен клієнт підключиться не безпосередньо до api, а до проксі-сервера, який несе відповідальність за фільтрацію даних відповідно до ролей цього користувача "
Клітон

Відповіді:


11

Ви повинні архітектуру API навколо ресурсів, а не навколо ролей, наприклад:

/rest/students

має бути доступним для всіх, хто має роль, яка дозволяє їм бачити учнів.

Внутрішньо ви реалізуєте захист на основі ролей. Те, як ви вирішите це, залежить від деталей вашої заявки, але скажімо, у вас є таблиця ролей, у кожної людини є одна або кілька ролей, і ці ролі визначають, що може отримати кожна людина. Ви вже вказали правила доступу до студентів:

  • студенти можуть отримати доступ до учнів у класах, які вони беруть
  • викладачі можуть отримати доступ до учнів у класах, які вони викладають

Тож коли людина телефонує:

/rest/students

ви називаєте метод, який звертається до учнів, переходячи в ролі людини. Ось псевдокод:

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

і в цьому методі ви можете отримати учнів для кожної ролі окремими дзвінками, наприклад:

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
  }
}

Це дуже груба ідея того, що ви могли б зробити, і це не обов'язково буде відповідати вашим конкретним потребам, але це повинно дати вам відчуття участі в роботі. Якщо ви хочете повернути заняття з кожним перерахованим студентом, це хороший підхід. Якщо ви просто хочете учнів, ви можете витягнути їх з кожного класу і об'єднати їх у колекцію учнів.

Ні, у вас не повинно бути окремого сховища на роль. Усі ролі полягають у тому, щоб визначити, як ви отримуєте дані, а можливо, що ви можете зробити з даними (наприклад, вчителі можуть вводити оцінки учнів). Самі дані однакові.

Що стосується шаблонів, то цей підхід використовує Factory Pattern, щоб абстрагувати службу, яка отримує дані на основі ролі. Можливо, а може і не доцільно мати окремі служби за роллю. Мені подобається такий підхід, оскільки він мінімізує кількість коду на кожному етапі програми і робить його більш читабельною, ніж комутатор або блок.


1
Дякую за відповідь. Я в кінцевому підсумку робив щось на кшталт того, що ти запропонував. Використовуючи LINQ2SQL (C #), я міг би передати запит до кожної "ролі" і застосувати де для кожної ролі, яку отримав користувач. Результатом цього буде оператор sql з умовою "АБО" для кожної ролі, до якої користувач має доступ. Якщо жодна роль не призначена користувачеві, я просто повертаю Enumarable.Empty () абонента.
Каспер Йенсен

0

Знайдіть ручку та папір та починайте моделювати свою систему.

Ви побачите, що вам, ймовірно, потрібна сутність домену під назвою ОСОБА. Оскільки і СТУДЕНТИ, і ВЧИТЕЛЬ "є-а" ОСОБА, ви можете створити абстрактне ціле під назвою ОСОБА з такими загальними атрибутами, як ім'я, прізвище тощо. Тепер ви можете спробувати знайти характеристики для ВЧИТЕЛЯ, які не стосуються СТУДЕНТІВ; наприклад, ВЧИТЕЛЬ викладає КЛАСИ щодо одного або декількох ТЕМУ.

Забезпечення безпеки вважається нефункціональним аспектом вашої програми. Це наскрізна проблема, з якою слід звертатися поза вашою "бізнес-логікою". Як зазначає @Robert Munn, РОЛІ (-и) повинні підтримуватися в одному місці. Використання ролей для обмеження доступу до певних функцій є досить грубим, а концепція називається рольовим управлінням доступу (RBAC).

Щоб перевірити, чи слід вчителю дозволити бачити оцінку учнів, слід вказати його у вашій моделі домену. Скажіть, у вчителя є клас з предметного програмування. Ви, напевно, виражаєте у своїй моделі, що студенти відвідують заняття з різних предметів. Тут починається логіка програми та бізнесу. Це логіка, яку ви можете перевірити, використовуючи тестові розробки.

Ви повинні розділити свої ресурси, щоб зробити вашу програму тестовою та модульною.

У будь-якому випадку, найкращий спосіб дійсно показати те, що я маю на увазі - це показати його з кодом :) Ось сторінка GitHub: https://github.com/thomasandersen77/role-based-rest-api

Удачі :)


3
ваше посилання пішло ...
Клейтон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.