Де повинні проходити перевірки дозволів користувачів і в MVC та ким?


26

Чи повинні проводитись перевірки дозволів користувача у моделі чи контролері? І хто повинен обробляти перевірки дозволів, об’єкт User або якийсь помічник UserManagement?

Де це повинно відбутися?

Перевірка в контролері:

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

Здійснення перевірок у контролері допомагає робити Моделі простими діями, тому ми можемо зберігати всю логіку щодо контролерів.

Перевірка в моделі:

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

Встановлюючи чеки в Модель, ми ускладнюємо Модель, але також переконуємось, що ми випадково не дозволяємо користувачам робити речі, які вони не повинні містити в Контролері.

А ким?

Як тільки ми оселимось на місці, хто повинен робити чеки? Користувач?

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

Але це не дійсно відповідальність користувача знати те, що він / вона може отримати, тому, можливо, якийсь клас помічників?

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

Я знаю, що звичайно задавати лише одне запитання, ну, питання, але я думаю, що на них можна відповісти чудово разом.

Відповіді:


20

Як завжди, "це залежить"

  • перевірки дозволу функціонально працюватимуть де завгодно зручніше,
  • але якщо ви задаєте технічне запитання, то відповідь може бути "поставити чеки в об'єкт, який володіє даними, необхідними для здійснення перевірки" (який, мабуть, є контролером).
  • але якщо ви ставите філософське питання, пропоную альтернативну відповідь: не показуйте користувачам дії, які їм заборонено виконувати .

Отже, в останньому випадку ви можете мати перевірку дозволу в контролері, реалізованому як булева властивість, і прив'язати це властивість до властивості Visible кнопки або панелі в інтерфейсі користувача, який контролює дію

як користувачеві неприємно бачити кнопки для дій, які я не можу виконати; відчуває, що я залишаюсь від задоволення;)


Наш додаток реалізує третій сценарій за винятком того, що ми не приховуємо елементи керування, ми їх вимикаємо. На жаль, це все робиться в коді Winforms, тому це не дуже важливо для питання про ОП.
Дейв Най

11
"засмучує бачити кнопки для дій, які я не можу виконувати" -> Спробуйте підняти свій власний пост :)
Rowan Freeman,

5
Недостатньо просто приховати кнопки для дій, які користувач не може виконувати, сервер повинен перевіряти кожен запит на отримання дозволів. Третій пункт кулі не є "альтернативною відповіддю", це щось робити, крім перевірки наявності дозволів на стороні сервера.
Flimm

@Flimm погодився, якщо запити обробляються сервером; конкретне питання стосувалося класу Controller
Стівен А. Лоу

7

Безпека є наскрізною проблемою, тому її потрібно впроваджувати в декілька шарів. Далі йде приклад для MVC, але ця концепція стосується інших архітектур та / або шаблонів, вам просто потрібно визначити точки примусового виконання.

Де це повинно відбутися?

Перегляди можуть містити елементи інтерфейсу користувача (віджети, кнопки, меню тощо), які потрібно відображати чи не для деяких користувачів, виходячи з їх дозволів. Це може бути відповідальністю механізму перегляду , тому що ви не хочете, щоб кожен вид поводився з цим самостійно. Залежно від типу елементів, на які ви робите авторизацію, холодно перемістіть цю відповідальність в інше місце. Наприклад, придумайте меню, в якому деякі елементи мають відображатися, а деякі - ні. Елементи можна десь реалізувати як список і відфільтрувати цей список на основі дозволів, а потім переслати його перегляду.

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

Ресурси відображаються на основі дозволів. Зазвичай це робиться на рівні бази даних , оскільки ви не хочете витягувати все з бази даних, а потім застосовувати дозволи.

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

Хто повинен це робити?

Очевидно не модель. Кожен шар повинен мати точку примусового виконання, яка обробляє авторизацію. Текст у курсиві вище висвітлює можливу точку виконання для кожного рівня.

Погляньте на XACML . Вам не доведеться реалізовувати це так, як є, але це дасть вам декілька вказівок, які ви могли б виконати.


Це найкраща відповідь. Чомусь верхні та інші мають справу з відмінностями між контролером і видом, або видом і моделлю, що не те, про що задається ОП. Спасибі!
redFur

1

Я використовую наступну схему. Варто сказати, що більшість перевірок прав користувачів можна розділити на два загальних випадки:

  • доступ користувача до дії контролера на основі ролі користувача без перевірки параметрів дії викликається,
  • доступ користувача до моделі, заснований на будь-якій логіці або відносинах між конкретним користувачем і конкретною моделлю.

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

Доступ користувача до певної моделі повинен бути визначений у моделі. (Актор - базовий клас користувача. Припустимо, це може бути або клієнт, і продавець, або гість.)

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

Внесення цієї логіки в модель приносить певний прибуток. Метод перевірки доступу може бути успадкований, вам не потрібно створювати зайвих класів, ви можете використовувати загальні переваги OOP.

Далі, щоб спростити перевірку доступу, ми беремо деякі припущення, які майже завжди реалізовані вже для простоти та гарного стилю:

  • зазвичай контролери пов'язані з деяким модельним класом;
  • дії, які перевіряються на доступ, беруть єдиний ідентифікатор моделі як параметр;
  • до цього параметра завжди можна отримати доступ однаково з методу базового класу контролера;
  • дія розміщується в контролері відповідно до моделі, яка виконує дію id.

За допомогою цих припущень дії, які використовують ідентифікатор моделі, можуть бути пов'язані з конкретним екземпляром моделі. Насправді більшість дій можна легко перетворити і перенести на відповідні припущення, викладені вище.

Потім слід визначити і успадкувати деякий базовий абстрактний клас контролера.

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

Ви можете викликати метод SomeController :: checkModelAccess ($ id), коли ви створюєте меню та вирішите, чи потрібно показувати якесь посилання.


Мені шкода PHP.
Георгій Совєтов

1

Як у моделі, так і в перегляді

У перегляді - оскільки інтерфейс користувача не повинен відображати елементи інтерфейсу, обмежені поточним користувачем

(наприклад, кнопка "Видалити" повинна бути показана людям з відповідними дозволами)

У моделі - тому що ваш додаток, ймовірно, має якийсь API, правда? API також повинен перевірити дозволи та, ймовірно, повторно використовувати модель.

(як, скажімо, у вас є кнопка "Видалити" в інтерфейсі користувача і метод API http: / server / API / DeleteEntry / 123 "одночасно


Чому ви вибрали модель над контролером?
Flimm

не впевнений, чому перегляд, модель, а не в контролері, де це робиться більшість часу.
ВП.

@VP у контролера немає можливості показувати / приховувати елементи інтерфейсу (крім передачі bool-var ДО
ПОГЛЯДУ

Я не знаю, скрізь це робиться в шарі контролера, тому мені було цікаво.
ВП.

0

MVC - схема презентації. Як такий вигляд, так і контролер повинен мати лише відповідальність щодо презентації. Деякі дозволи застосовуються до презентації, як, наприклад, експертний режим, експериментальні функції інтерфейсу або різні конструкції. З ними може працювати MVC-контролер.

Багато інших видів дозволів є актуальними для декількох шарів програми. Наприклад, якщо ви хочете мати користувачів, які можуть переглядати лише дані, а не змінювати речі:

  • презентаційний шар повинен приховувати можливості редагування
  • Якщо функція редагування все-таки викликається, це могло б / слід виявити (за допомогою програми, конкретних частин бізнес-шару, а не конкретної доменної частини - TrainEditor, а не Train) і, ймовірно, спричинити виняток
  • Рівень доступу до даних також може перевіряти наявність записів, але для складніших дозволів, які швидко вимагають занадто багато знань про бізнес-рівень, щоб бути гарною ідеєю.

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

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