| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 | <?phpnamespace common\modules\rbac\components;use Yii;use yii\base\Module;use yii\di\Instance;use yii\web\ForbiddenHttpException;use yii\web\User;/** * Access Control Filter (ACF) is a simple authorization method that is best used by applications that only need some simple access control.  * As its name indicates, ACF is an action filter that can be attached to a controller or a module as a behavior.  * ACF will check a set of access rules to make sure the current user can access the requested action. * * To use AccessControl, declare it in the application config as behavior. * For example. * * ~~~ * 'as access' => [ *     'class' => 'rbac\components\AccessControl', *     'allowActions' => ['site/login', 'site/error'] * ] * ~~~ * * @property User $user *  * @author Misbahul D Munir <misbahuldmunir@gmail.com> * * @since 1.0 */class AccessControl extends \yii\base\ActionFilter{    /**     * @var User User for check access.     */    private $_user = 'user';    /**     * @var array List of action that not need to check access.     */    public $allowActions = [];    /**     * Get user.     *     * @return User     */    public function getUser()    {        if (!$this->_user instanceof User) {            $this->_user = Instance::ensure($this->_user, User::className());        }        return $this->_user;    }    /**     * Set user.     *     * @param User|string $user     */    public function setUser($user)    {        $this->_user = $user;    }    /**     * {@inheritdoc}     */    public function beforeAction($action)    {        $actionId = $action->getUniqueId();        $user = $this->getUser();        if ($user->can('/'.$actionId)) {            return true;        }        $obj = $action->controller;        do {            if ($user->can('/'.ltrim($obj->getUniqueId().'/*', '/'))) {                return true;            }            $obj = $obj->module;        } while ($obj !== null);        $this->denyAccess($user);    }    /**     * Denies the access of the user.     * The default implementation will redirect the user to the login page if he is a guest;     * if the user is already logged, a 403 HTTP exception will be thrown.     *     * @param \yii\web\User $user the current user     *     * @throws \yii\web\ForbiddenHttpException if the user is already logged in.     */    protected function denyAccess($user)    {        if ($user->getIsGuest()) {            $user->loginRequired();        } else {            throw new ForbiddenHttpException(Yii::t('yii', 'You are not allowed to perform this action.'));        }    }    /**     * {@inheritdoc}     */    protected function isActive($action)    {        $uniqueId = $action->getUniqueId();        if ($uniqueId === Yii::$app->getErrorHandler()->errorAction) {            return false;        }        $user = $this->getUser();        if ($user->getIsGuest() && is_array($user->loginUrl) && isset($user->loginUrl[0]) && $uniqueId === trim($user->loginUrl[0], '/')) {            return false;        }        if ($this->owner instanceof Module) {            // convert action uniqueId into an ID relative to the module            $mid = $this->owner->getUniqueId();            $id = $uniqueId;            if ($mid !== '' && strpos($id, $mid.'/') === 0) {                $id = substr($id, strlen($mid) + 1);            }        } else {            $id = $action->id;        }        foreach ($this->allowActions as $route) {            if (substr($route, -1) === '*') {                $route = rtrim($route, '*');                if ($route === '' || strpos($id, $route) === 0) {                    return false;                }            } else {                if ($id === $route) {                    return false;                }            }        }        if ($action->controller->hasMethod('allowAction') && in_array($action->id, $action->controller->allowAction())) {            return false;        }        return true;    }}
 |