Управление общедоступными методами вызывающего контроллера, возможно ли это?

#php

#php

Вопрос:

Задача состоит в том, чтобы защитить вызывающие методы общедоступного контроллера; нам нужно проверить, является ли пользователь администратором или нет перед вызовом.

 class AdminController {

    final public function __call($name, $arguments) {
        if (!Auth::isAuth()) {
            $User = UserFactory::loadById(Auth::getUserId());
            if (!$User->isAdmin()) {
                throw new ForbiddenException();
            }
        }
        return call_user_func_array(array($this, $name), $arguments);
    }

}

class AdminCategoryController extends AdminController {

    public function view() { //__call() won't be called bacause it is public method

    }

}
  

Мы можем использовать волшебный __call() метод, но нам нужно, чтобы все методы были private .

Другой способ, который я вижу, — определить final public __construct() at AdminController и поставить там проверку $User-> isAdmin()…

Есть еще идеи?

Спасибо.

Ответ №1:

Создайте новый метод в вашем базовом контроллере ( BaseController ), вызываемый isSecure() :

 public function isSecure() {
    return false;
}
  

Затем в вашем контроллере, который должен быть безопасным ( AdminBaseController ), переопределите метод с помощью:

 public function isSecure() {
    return true;
}
  

AdminBaseController распространяется BaseController и AdminCategoryController должен расширяться AdminBaseController .

Затем в любой момент вы можете вызвать $Controller->isSecure() любой контроллер, чтобы выяснить, должен ли он быть безопасным или нет.

Итак, в вашем коде отправки вы могли бы использовать что-то вроде этого (очевидно, требуется рефакторинг):

 if($Controller->isSecure()) {
    if (!Auth::isAuth()) {
        $User = UserFactory::loadById(Auth::getUserId());
        if (!$User->isAdmin()) {
            throw new ForbiddenException();
        }
    } else {
        $Controller->view();
    }
}
  

Комментарии:

1. Зачем нам нужно внедрять isSecure метод? Будучи дочерним элементом AdminController = все методы вызываются безопасно. Реализация isSecure() метода в порядке, если у меня нет отдельных контроллеров для администратора / общественности. Кстати, мне кажется, что лучше определить isSecure в корневом контроллере, а затем определить constanct IS_SECURE для каждого дочернего контроллера.

2. Таким образом, ваш код отправки может проверять перед вызовом контроллера. Ваш диспетчер должен направлять пользователя к InvalidLoginController или чему-то подобному, а не к *AdminController , если они не авторизованы. Я немного пересмотрел свой ответ, пока вы комментировали. Я предлагаю вам перехватывать не прошедших проверку подлинности пользователей на уровень выше контроллера в вашем коде отправки.

3. Ага, понятно. Итак, проверка IsCallable в dispatcher позволит нам реализовать полнофункциональный ACL. Отлично!