AccessControl.php 4.98 KB
Newer Older
1 2 3 4 5 6 7
<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

8
namespace yii\filters;
9 10 11 12

use Yii;
use yii\base\Action;
use yii\base\ActionFilter;
13 14
use yii\web\User;
use yii\web\ForbiddenHttpException;
15 16

/**
17 18 19 20 21
 * AccessControl provides simple access control based on a set of rules.
 *
 * AccessControl is an action filter. It will check its [[rules]] to find
 * the first rule that matches the current context variables (such as user IP address, user role).
 * The matching rule will dictate whether to allow or deny the access to the requested controller
22
 * action. If no rule matches, the access will be denied.
23 24 25 26 27 28 29 30
 *
 * To use AccessControl, declare it in the `behaviors()` method of your controller class.
 * For example, the following declarations will allow authenticated users to access the "create"
 * and "update" actions and deny all other users from accessing these two actions.
 *
 * ~~~
 * public function behaviors()
 * {
Alexander Makarov committed
31 32
 *     return [
 *         'access' => [
33
 *             'class' => \yii\filters\AccessControl::className(),
Alexander Makarov committed
34 35
 *             'only' => ['create', 'update'],
 *             'rules' => [
36
 *                 // deny all POST requests
Alexander Makarov committed
37
 *                 [
38
 *                     'allow' => false,
Alexander Makarov committed
39 40
 *                     'verbs' => ['POST']
 *                 ],
41
 *                 // allow authenticated users
Alexander Makarov committed
42
 *                 [
43
 *                     'allow' => true,
Alexander Makarov committed
44 45
 *                     'roles' => ['@'],
 *                 ],
46
 *                 // everything else is denied
Alexander Makarov committed
47 48 49
 *             ],
 *         ],
 *     ];
50 51
 * }
 * ~~~
52 53 54 55 56 57
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @since 2.0
 */
class AccessControl extends ActionFilter
{
58 59 60 61 62 63 64 65 66 67 68
    /**
     * @var callable a callback that will be called if the access should be denied
     * to the current user. If not set, [[denyAccess()]] will be called.
     *
     * The signature of the callback should be as follows:
     *
     * ~~~
     * function ($rule, $action)
     * ~~~
     *
     * where `$rule` is this rule, and `$action` is the current [[Action|action]] object.
69
     * `$rule` will be `null` if access is denied because none of the rules matched.
70 71 72 73 74 75
     */
    public $denyCallback;
    /**
     * @var array the default configuration of access rules. Individual rule configurations
     * specified via [[rules]] will take precedence when the same property of the rule is configured.
     */
76
    public $ruleConfig = ['class' => 'yii\filters\AccessRule'];
77 78 79 80 81 82 83
    /**
     * @var array a list of access rule objects or configuration arrays for creating the rule objects.
     * If a rule is specified via a configuration array, it will be merged with [[ruleConfig]] first
     * before it is used for creating the rule object.
     * @see ruleConfig
     */
    public $rules = [];
84

85

86 87 88 89 90 91 92 93 94 95 96 97
    /**
     * Initializes the [[rules]] array by instantiating rule objects from configurations.
     */
    public function init()
    {
        parent::init();
        foreach ($this->rules as $i => $rule) {
            if (is_array($rule)) {
                $this->rules[$i] = Yii::createObject(array_merge($this->ruleConfig, $rule));
            }
        }
    }
98

99 100 101
    /**
     * This method is invoked right before an action is to be executed (after all possible filters.)
     * You may override this method to do last-minute preparation for the action.
102
     * @param Action $action the action to be executed.
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
     * @return boolean whether the action should continue to be executed.
     */
    public function beforeAction($action)
    {
        $user = Yii::$app->getUser();
        $request = Yii::$app->getRequest();
        /** @var AccessRule $rule */
        foreach ($this->rules as $rule) {
            if ($allow = $rule->allows($action, $user, $request)) {
                return true;
            } elseif ($allow === false) {
                if (isset($rule->denyCallback)) {
                    call_user_func($rule->denyCallback, $rule, $action);
                } elseif (isset($this->denyCallback)) {
                    call_user_func($this->denyCallback, $rule, $action);
                } else {
                    $this->denyAccess($user);
                }
                return false;
            }
        }
        if (isset($this->denyCallback)) {
125
            call_user_func($this->denyCallback, null, $action);
126 127 128 129 130 131 132 133 134 135
        } else {
            $this->denyAccess($user);
        }
        return false;
    }

    /**
     * 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.
136
     * @param User $user the current user
137 138 139 140 141 142 143 144 145 146
     * @throws 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.'));
        }
    }
Zander Baldwin committed
147
}