yii1.x局部禁用csrf验证的例子

作者:袖梨 2022-06-25

首先分析下原因:

 

当你在配置文件中打开csrf:

'request'=>array(
   'enableCsrfValidation'=>true,
),
全局都会对post请求作csrf验证,那么当我开发对外接口时该怎么办?微信、微博什么的可不会配合你的csrf机制,唯一的办法就是只对这些接口请求关闭csrf,但不影响其他业务。

 

事先的想法是,在某个地方通过改变 enableCsrfValidation 的值来关闭csrf验证,比如一开始我是这么尝试的:

 

在控制器的beforeAction或init方法中加上一句代码:

Yii::app()->request->enableCsrfValidation = false;
失败了,失败了,失败了!重要的事说三遍。

 

这尼玛该咋办?没办法只能浪费时间去看框架源码,结果发现它在CHttpRequest中是这么处理的:

if($this->enableCsrfValidation)
   Mod::app()->attachEventHandler('onBeginRequest',array($this,'validateCsrfToken'));


这尼玛,直接放到 Application 的 onBeginRequest 事件中去了,因为发生在控制器加载之前,控制器中做啥都没用!

 

ok,想办法:

新建一个MyApplication类继承CWebApplication,并重写onBeginRequest类,通过某些判断绕过validateCsrfToken动作。

很明显方案1太麻烦,这蹩脚的事件机制我根本不想动它,于是我采用了下面的办法。

 

 

我的办法:

 

首先,配置文件中关闭csrf

'request'=>array(
   'enableCsrfValidation'=>false,//强制关闭,否则影响接口服务,转为控制器中手动验证。
),
然后,打开 components/Controller.php,这样写:

class Controller extends CController
{

   public $enableCSRF=true;//是否开启csrf验证

   //执行action前的处理
   public function beforeAction($action)
   {
      $this->validateCsrfToken();
      return parent::beforeAction($action);
   }


   //验证csrf
   protected function validateCsrfToken()
   {
      if ($this->enableCSRF == true) {
         Mod::app()->request->enableCsrfValidation = true;//属性改为true,以便CHtml::beginForm()生成csrf_token

         try{
            Mod::app()->request->validateCsrfToken(null);//验证csrf
         } catch(Exception $e) {
            Mod::app()->handleException($e);
         }
      }
   }
}


主要是通过控制器基类的 beforeAction 来拦截请求,通过条件判断来手动调用csrf验证。如果某个控制器不想csrf验证,那么在子控制器中设置

public $enableCSRF = false;
即可关闭校验。

相关文章

精彩推荐