AccessRule.php 5.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

namespace yii\web;

use yii\base\Component;
use yii\base\Action;

/**
14
 * This class represents an access rule defined by the [[AccessControl]] action filter
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @since 2.0
 */
class AccessRule extends Component
{
	/**
	 * @var boolean whether this is an 'allow' rule or 'deny' rule.
	 */
	public $allow;
	/**
	 * @var array list of action IDs that this rule applies to. The comparison is case-sensitive.
	 * If not set or empty, it means this rule applies to all actions.
	 */
	public $actions;
	/**
	 * @var array list of controller IDs that this rule applies to. The comparison is case-sensitive.
	 * If not set or empty, it means this rule applies to all controllers.
	 */
	public $controllers;
	/**
Qiang Xue committed
36 37
	 * @var array list of roles that this rule applies to. Two special roles are recognized, and
	 * they are checked via [[User::isGuest]]:
38 39 40 41
	 *
	 * - `?`: matches a guest user (not authenticated yet)
	 * - `@`: matches an authenticated user
	 *
Qiang Xue committed
42
	 * Using additional role names requires RBAC (Role-Based Access Control), and
Qiang Xue committed
43
	 * [[User::checkAccess()]] will be called.
Qiang Xue committed
44 45
	 *
	 * If this property is not set or empty, it means this rule applies to all roles.
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
	 */
	public $roles;
	/**
	 * @var array list of user IP addresses that this rule applies to. An IP address
	 * can contain the wildcard `*` at the end so that it matches IP addresses with the same prefix.
	 * For example, '192.168.*' matches all IP addresses in the segment '192.168.'.
	 * If not set or empty, it means this rule applies to all IP addresses.
	 * @see Request::userIP
	 */
	public $ips;
	/**
	 * @var array list of request methods (e.g. `GET`, `POST`) that this rule applies to.
	 * The request methods must be specified in uppercase.
	 * If not set or empty, it means this rule applies to all request methods.
	 * @see Request::requestMethod
	 */
	public $verbs;
	/**
	 * @var callback a callback that will be called to determine if the rule should be applied.
	 * 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.
	 * The callback should return a boolean value indicating whether this rule should be applied.
	 */
	public $matchCallback;
	/**
	 * @var callback a callback that will be called if this rule determines the access to
	 * the current action should be denied. If not set, the behavior will be determined by
	 * [[AccessControl]].
	 *
	 * 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.
	 */
	public $denyCallback;


	/**
	 * Checks whether the Web user is allowed to perform the specified action.
	 * @param Action $action the action to be performed
	 * @param User $user the user object
	 * @param Request $request
	 * @return boolean|null true if the user is allowed, false if the user is denied, null if the rule does not apply to the user
	 */
	public function allows($action, $user, $request)
	{
		if ($this->matchAction($action)
			&& $this->matchRole($user)
			&& $this->matchIP($request->getUserIP())
103
			&& $this->matchVerb($request->getMethod())
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
			&& $this->matchController($action->controller)
			&& $this->matchCustom($action)
		) {
			return $this->allow ? true : false;
		} else {
			return null;
		}
	}

	/**
	 * @param Action $action the action
	 * @return boolean whether the rule applies to the action
	 */
	protected function matchAction($action)
	{
		return empty($this->actions) || in_array($action->id, $this->actions, true);
	}

	/**
	 * @param Controller $controller the controller
	 * @return boolean whether the rule applies to the controller
	 */
	protected function matchController($controller)
	{
128
		return empty($this->controllers) || in_array($controller->uniqueId, $this->controllers, true);
129 130 131 132 133 134 135 136 137 138 139 140
	}

	/**
	 * @param User $user the user object
	 * @return boolean whether the rule applies to the role
	 */
	protected function matchRole($user)
	{
		if (empty($this->roles)) {
			return true;
		}
		foreach ($this->roles as $role) {
Qiang Xue committed
141 142 143 144
			if ($role === '?' && $user->getIsGuest()) {
				return true;
			} elseif ($role === '@' && !$user->getIsGuest()) {
				return true;
Qiang Xue committed
145
			} elseif ($user->checkAccess($role)) {
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
				return true;
			}
		}
		return false;
	}

	/**
	 * @param string $ip the IP address
	 * @return boolean whether the rule applies to the IP address
	 */
	protected function matchIP($ip)
	{
		if (empty($this->ips)) {
			return true;
		}
		foreach ($this->ips as $rule) {
			if ($rule === '*' || $rule === $ip || (($pos = strpos($rule, '*')) !== false && !strncmp($ip, $rule, $pos))) {
				return true;
			}
		}
		return false;
	}

	/**
	 * @param string $verb the request method
	 * @return boolean whether the rule applies to the request
	 */
	protected function matchVerb($verb)
	{
		return empty($this->verbs) || in_array($verb, $this->verbs, true);
	}

	/**
	 * @param Action $action the action to be performed
	 * @return boolean whether the rule should be applied
	 */
	protected function matchCustom($action)
	{
		return empty($this->matchCallback) || call_user_func($this->matchCallback, $this, $action);
	}
Zander Baldwin committed
186
}