API REST на основе ролей?

27

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

Для простоты, давайте возьмем домен "ученик / учитель / класс":

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

У пользователей могут быть роли, такие как Студент и / или Учитель

Студенты будут иметь доступ только к ученикам своих классов. Учителя будут иметь доступ к ученикам классов, которые они преподают. В некоторых случаях ученик И может преподавать и другие классы. Они должны иметь доступ к ученикам своих классов и ученикам классов, которые они преподают.

В идеале я хочу реализовать это как две функции - по одной на роль и затем «объединение», если у пользователя несколько ролей.

Мой вопрос: какой шаблон я должен использовать для реализации этого?

внешне

  • Должен ли я разделить свой API на роль? GET /teacher/studentsи GET /student/studentsэто не кажется мне правильным.
  • Держите все это я один ресурс (предпочтительно)

внутренне

Как это должно быть реализовано внутри?

  • Должен ли каждый метод начинаться с БОЛЬШОГО переключателя / если для каждой роли?
  • Должен ли я реализовать хранилище для каждой роли?
  • Есть ли шаблон дизайна, который поможет мне в достижении этого?

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

Каспер Дженсен
источник
3
«Это отличный вопрос, я хотел бы знать, если вы пришли с решением для этого, потому что я пытаюсь сделать что-то подобное. Что я думаю, что должно быть: во-первых, мы реализуем API, который возвращает все необходимые данные тогда каждый клиент будет подключаться не напрямую к API, а к прокси-серверу, который будет отвечать за фильтрацию данных в соответствии с ролями этого пользователя "
Cleiton

Ответы:

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

Найдите ручку и бумагу и начните моделировать свою систему.

Вы обнаружите, что вам, вероятно, нужен доменный объект с именем PERSON. Поскольку и STUDENTS, и TEACHER «is-a» PERSON, вы можете создать абстрактную сущность с именем PERSON с общими атрибутами, такими как имя, фамилия и т. Д. A TEACHER -> is-a -> Person. Теперь вы можете попытаться найти характеристики для УЧИТЕЛЯ, которые не относятся к СТУДЕНТАМ; например, УЧИТЕЛЬ преподает КЛАСС (ы) относительно одного или нескольких ПРЕДМЕТОВ.

Обеспечение безопасности считается нефункциональным аспектом вашего приложения. Это сквозная проблема, которая должна решаться за пределами вашей «бизнес-логики». Как указывает @Robert Munn, РОЛЬ (и) должны храниться в одном месте. Использование ролей для ограничения доступа к определенным функциям довольно грубо, и эта концепция называется управлением доступом на основе ролей (RBAC).

Чтобы проверить, разрешено ли учителю видеть оценки учеников, это должно быть выражено в вашей доменной модели. Скажем, у учителя есть класс по предмету программирования. Вы, вероятно, скажете в своей модели, что студенты посещают занятия по разным предметам. Вот где начинает действовать прикладная / бизнес-логика. Это логика, которую вы можете проверить с помощью разработки через тестирование.

Вы должны разделить свои ресурсы, чтобы сделать приложение тестируемым и модульным.

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

Удачи :)

Томас Андерсен
источник
3
Ваша ссылка исчезла ...
Клитон