YII 局部CSRF、令牌使用sessio存储

YII 自带的CSRF功能很强大,每个form提交的数都会进行令牌验证,导致在接收支付宝同步通知时,被YII的CSRF功能挡之门外。项目中可能有些地方需要进行CSRF验证,但是有些地方又不需要。YII2在顶级控制器中添加了关闭csrf的一个属性:
/**
 * @var boolean whether to enable CSRF validation for the actions in this controller.
 * CSRF validation is enabled only when both this property and [[Request::enableCsrfValidation]] are true.
*/
 public $enableCsrfValidation = true;

但是yii2.0以下的版本是没有这个属性的。这是就得重写HttpRequest组件了。

<?php
class HttpRequest extends CHttpRequest{

    public $noCsrfValidationRoutes=array();

    //将CSRF令牌存入session
    /**
    +----------------------------------------------------------
     * 重写CHttpRequest中getCsrfToken方法
    +----------------------------------------------------------
     * author   fujia<@.com>
     * time     2015年4月27日20:47:54
    +----------------------------------------------------------
     */
    public function getCsrfToken(){
        if($this->_csrfToken===null)
        {
            $session = Yii::app()->session;
            $csrfToken=$session->itemAt($this->csrfTokenName);

            if($csrfToken===null)
            {
                $csrfToken = sha1(uniqid(mt_rand(),true));
                $session->add($this->csrfTokenName, $csrfToken);
            }
            $this->_csrfToken = $csrfToken;
        }

        return $this->_csrfToken;
    }

    //将使用session验证
    public function validateCsrfToken($event)
    {

        if($this->getIsPostRequest())
        {
            // only validate POST requests
            $session=Yii::app()->session;
            if($session->contains($this->csrfTokenName) && isset($_POST[$this->csrfTokenName]))
            {
                $tokenFromSession=$session->itemAt($this->csrfTokenName);
                $tokenFromPost=$_POST[$this->csrfTokenName];
                $valid=$tokenFromSession===$tokenFromPost;
            }
            else
            $valid=false;
            if(!$valid)
                throw new CHttpException(400,Yii::t('yii','The CSRF token could not be verified.'));
        }
    }
    //重写httprequest中的方法
    protected function normalizeRequest()
    {
        parent::normalizeRequest();

        //remove the event handler CSRF if this is a route we want skipped
        if($this->enableCsrfValidation)
        {
            $url=Yii::app()->getUrlManager()->parseUrl($this);
            foreach($this->noCsrfValidationRoutes as $route)
            {

                if(strpos($url,$route)===0)

                $result = Yii::app()->detachEventHandler('onBeginRequest',array($this,'validateCsrfToken'));
            }
        }
    }


}
在配置文件中加:

'request'=>array(
			'class' => 'cfg_common.components.HttpRequest',
            'enableCsrfValidation'=>true,
            'enableCookieValidation'=>true,
            'noCsrfValidationRoutes'=>array(//不需要CSEF验证的URL
				'goods/cart',
				'goods/getOrder',
				'orders/notifyUrl',
				'orders/returnUrl',
				'orders/notifyUrlWap',
				'orders/returnUrlWap',
				'index/saveOrder',
			),
        ),
最后搞定


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章