Вход Регистрация
Файл: framework/web/auth/CAccessControlFilter.php
Строк: 435
<?php
/**
 * CAccessControlFilter class file.
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @link http://www.yiiframework.com/
 * @copyright 2008-2013 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

/**
 * CAccessControlFilter performs authorization checks for the specified actions.
 *
 * By enabling this filter, controller actions can be checked for access permissions.
 * When the user is not denied by one of the security rules or allowed by a rule explicitly,
 * he will be able to access the action.
 *
 * For maximum security consider adding
 * <pre>array('deny')</pre>
 * as a last rule in a list so all actions will be denied by default.
 *
 * To specify the access rules, set the {@link setRules rules} property, which should
 * be an array of the rules. Each rule is specified as an array of the following structure:
 * <pre>
 * array(
 *   'allow',  // or 'deny'
 * 
 *   // optional, list of action IDs (case insensitive) that this rule applies to
 *   // if not specified or empty, rule applies to all actions
 *   'actions'=>array('edit', 'delete'),
 * 
 *   // optional, list of controller IDs (case insensitive) that this rule applies to
 *   'controllers'=>array('post', 'admin/user'),
 * 
 *   // optional, list of usernames (case insensitive) that this rule applies to
 *   // Use * to represent all users, ? guest users, and @ authenticated users
 *   'users'=>array('thomas', 'kevin'),
 * 
 *   // optional, list of roles (case sensitive!) that this rule applies to.
 *   'roles'=>array('admin', 'editor'),
 * 
 *   // since version 1.1.11 you can pass parameters for RBAC bizRules
 *   'roles'=>array('updateTopic'=>array('topic'=>$topic))
 * 
 *   // optional, list of IP address/patterns that this rule applies to
 *   // e.g. 127.0.0.1, 127.0.0.*
 *   'ips'=>array('127.0.0.1'),
 * 
 *   // optional, list of request types (case insensitive) that this rule applies to
 *   'verbs'=>array('GET', 'POST'),
 * 
 *   // optional, a PHP expression whose value indicates whether this rule applies
 *   // The PHP expression will be evaluated using {@link evaluateExpression}.
 *   // A PHP expression can be any PHP code that has a value. To learn more about what an expression is,
 *   // please refer to the {@link http://www.php.net/manual/en/language.expressions.php php manual}.
 *   'expression'=>'!$user->isGuest && $user->level==2',
 * 
 *   // optional, the customized error message to be displayed
 *   // This option is available since version 1.1.1.
 *   'message'=>'Access Denied.',
 * 
 *   // optional, the denied method callback name, that will be called once the
 *   // access is denied, instead of showing the customized error message. It can also be
 *   // a valid PHP callback, including class method name (array(ClassName/Object, MethodName)),
 *   // or anonymous function (PHP 5.3.0+). The function/method signature should be as follows:
 *   // function foo($user, $rule) { ... }
 *   // where $user is the current application user object and $rule is this access rule.
 *   // This option is available since version 1.1.11.
 *   'deniedCallback'=>'redirectToDeniedMethod',
  * )
 * </pre>
 *
 * @property array $rules List of access rules.
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @package system.web.auth
 * @since 1.0
 */
class CAccessControlFilter extends CFilter
{
    
/**
     * @var string the error message to be displayed when authorization fails.
     * This property can be overridden by individual access rule via {@link CAccessRule::message}.
     * If this property is not set, a default error message will be displayed.
     * @since 1.1.1
     */
    
public $message;

    private 
$_rules=array();

    
/**
     * @return array list of access rules.
     */
    
public function getRules()
    {
        return 
$this->_rules;
    }

    
/**
     * @param array $rules list of access rules.
     */
    
public function setRules($rules)
    {
        foreach(
$rules as $rule)
        {
            if(
is_array($rule) && isset($rule[0]))
            {
                
$r=new CAccessRule;
                
$r->allow=$rule[0]==='allow';
                foreach(
array_slice($rule,1) as $name=>$value)
                {
                    if(
$name==='expression' || $name==='roles' || $name==='message' || $name==='deniedCallback')
                        
$r->$name=$value;
                    else
                        
$r->$name=array_map('strtolower',$value);
                }
                
$this->_rules[]=$r;
            }
        }
    }

    
/**
     * Performs the pre-action filtering.
     * @param CFilterChain $filterChain the filter chain that the filter is on.
     * @return boolean whether the filtering process should continue and the action
     * should be executed.
     */
    
protected function preFilter($filterChain)
    {
        
$app=Yii::app();
        
$request=$app->getRequest();
        
$user=$app->getUser();
        
$verb=$request->getRequestType();
        
$ip=$request->getUserHostAddress();

        foreach(
$this->getRules() as $rule)
        {
            if((
$allow=$rule->isUserAllowed($user,$filterChain->controller,$filterChain->action,$ip,$verb))>0// allowed
                
break;
            elseif(
$allow<0// denied
            
{
                if(isset(
$rule->deniedCallback))
                    
call_user_func($rule->deniedCallback$rule);
                else
                    
$this->accessDenied($user,$this->resolveErrorMessage($rule));
                return 
false;
            }
        }

        return 
true;
    }

    
/**
     * Resolves the error message to be displayed.
     * This method will check {@link message} and {@link CAccessRule::message} to see
     * what error message should be displayed.
     * @param CAccessRule $rule the access rule
     * @return string the error message
     * @since 1.1.1
     */
    
protected function resolveErrorMessage($rule)
    {
        if(
$rule->message!==null)
            return 
$rule->message;
        elseif(
$this->message!==null)
            return 
$this->message;
        else
            return 
Yii::t('yii','You are not authorized to perform this action.');
    }

    
/**
     * Denies the access of the user.
     * This method is invoked when access check fails.
     * @param IWebUser $user the current user
     * @param string $message the error message to be displayed
     * @throws CHttpException
     */
    
protected function accessDenied($user,$message)
    {
        if(
$user->getIsGuest())
            
$user->loginRequired();
        else
            throw new 
CHttpException(403,$message);
    }
}


/**
 * CAccessRule represents an access rule that is managed by {@link CAccessControlFilter}.
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @package system.web.auth
 * @since 1.0
 */
class CAccessRule extends CComponent
{
    
/**
     * @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-insensitive.
     * If no actions are specified, rule applies to all actions.
     */
    
public $actions;
    
/**
     * @var array list of controller IDs that this rule applies to. The comparison is case-insensitive.
     */
    
public $controllers;
    
/**
     * @var array list of user names that this rule applies to. The comparison is case-insensitive.
     * If no user names are specified, rule applies to all users.
     */
    
public $users;
    
/**
     * @var array list of roles this rule applies to. For each role, the current user's
     * {@link CWebUser::checkAccess} method will be invoked. If one of the invocations
     * returns true, the rule will be applied.
     * Note, you should mainly use roles in an "allow" rule because by definition,
     * a role represents a permission collection.
     * @see CAuthManager
     */
    
public $roles;
    
/**
     * @var array IP patterns.
     */
    
public $ips;
    
/**
     * @var array list of request types (e.g. GET, POST) that this rule applies to.
     */
    
public $verbs;
    
/**
     * @var string a PHP expression whose value indicates whether this rule should be applied.
     * In this expression, you can use <code>$user</code> which refers to <code>Yii::app()->user</code>.
     * The expression can also be a valid PHP callback,
     * including class method name (array(ClassName/Object, MethodName)),
     * or anonymous function (PHP 5.3.0+). The function/method signature should be as follows:
     * <pre>
     * function foo($user, $rule) { ... }
     * </pre>
     * where $user is the current application user object and $rule is this access rule.
     *
     * The PHP expression will be evaluated using {@link evaluateExpression}.
     *
     * A PHP expression can be any PHP code that has a value. To learn more about what an expression is,
     * please refer to the {@link http://www.php.net/manual/en/language.expressions.php php manual}.
     */
    
public $expression;
    
/**
     * @var string the error message to be displayed when authorization is denied by this rule.
     * If not set, a default error message will be displayed.
     * @since 1.1.1
     */
    
public $message;
    
/**
     * @var mixed the denied method callback that will be called once the
     * access is denied. It replaces the behavior that shows an error message.
     * It can be a valid PHP callback including class method name (array(ClassName/Object, MethodName)),
     * or anonymous function (PHP 5.3.0+). For more information, on different options, check
     * @link http://www.php.net/manual/en/language.pseudo-types.php#language.types.callback
     * The function/method signature should be as follows:
     * <pre>
     * function foo($rule) { ... }
     * </pre>
     * where $rule is this access rule.
     *
     * @since 1.1.11
     */
    
public $deniedCallback;


    
/**
     * Checks whether the Web user is allowed to perform the specified action.
     * @param CWebUser $user the user object
     * @param CController $controller the controller currently being executed
     * @param CAction $action the action to be performed
     * @param string $ip the request IP address
     * @param string $verb the request verb (GET, POST, etc.)
     * @return integer 1 if the user is allowed, -1 if the user is denied, 0 if the rule does not apply to the user
     */
    
public function isUserAllowed($user,$controller,$action,$ip,$verb)
    {
        if(
$this->isActionMatched($action)
            && 
$this->isUserMatched($user)
            && 
$this->isRoleMatched($user)
            && 
$this->isIpMatched($ip)
            && 
$this->isVerbMatched($verb)
            && 
$this->isControllerMatched($controller)
            && 
$this->isExpressionMatched($user))
            return 
$this->allow : -1;
        else
            return 
0;
    }

    
/**
     * @param CAction $action the action
     * @return boolean whether the rule applies to the action
     */
    
protected function isActionMatched($action)
    {
        return empty(
$this->actions) || in_array(strtolower($action->getId()),$this->actions);
    }

    
/**
     * @param CController $controller the controller
     * @return boolean whether the rule applies to the controller
     */
    
protected function isControllerMatched($controller)
    {
        return empty(
$this->controllers) || in_array(strtolower($controller->getUniqueId()),$this->controllers);
    }

    
/**
     * @param IWebUser $user the user
     * @return boolean whether the rule applies to the user
     */
    
protected function isUserMatched($user)
    {
        if(empty(
$this->users))
            return 
true;
        foreach(
$this->users as $u)
        {
            if(
$u==='*')
                return 
true;
            elseif(
$u==='?' && $user->getIsGuest())
                return 
true;
            elseif(
$u==='@' && !$user->getIsGuest())
                return 
true;
            elseif(!
strcasecmp($u,$user->getName()))
                return 
true;
        }
        return 
false;
    }

    
/**
     * @param IWebUser $user the user object
     * @return boolean whether the rule applies to the role
     */
    
protected function isRoleMatched($user)
    {
        if(empty(
$this->roles))
            return 
true;
        foreach(
$this->roles as $key=>$role)
        {
            if(
is_numeric($key))
            {
                if(
$user->checkAccess($role))
                    return 
true;
            }
            else
            {
                if(
$user->checkAccess($key,$role))
                    return 
true;
            }
        }
        return 
false;
    }

    
/**
     * @param string $ip the IP address
     * @return boolean whether the rule applies to the IP address
     */
    
protected function isIpMatched($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 isVerbMatched($verb)
    {
        return empty(
$this->verbs) || in_array(strtolower($verb),$this->verbs);
    }

    
/**
     * @param IWebUser $user the user
     * @return boolean the expression value. True if the expression is not specified.
     */
    
protected function isExpressionMatched($user)
    {
        if(
$this->expression===null)
            return 
true;
        else
            return 
$this->evaluateExpression($this->expression, array('user'=>$user));
    }
}
Онлайн: 3
Реклама