zoukankan      html  css  js  c++  java
  • yii 2 局部关闭 CSRF 拦截

    最近在拿 yii 2.0 开发ajax提交,在 post 请求接口时,提示数据无法验证,于是查询 yii 错误日志,发现错误为

    exception ‘yiiwebBadRequestHttpException’ with message ‘Unable to verify your data submission

    于是查看源代码,yii 2.0 在 我们继承的顶级 controller 中,有下列属性

    /**
     * @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;

    106 行的 beforeAction 内,对他做了处理

    ``` public function beforeAction($action) { if (parent::beforeAction($action)) { if ($this->enableCsrfValidation && Yii::$app->getErrorHandler()->exception === null && !Yii::$app->getRequest()->validateCsrfToken()) { throw new BadRequestHttpException(Yii::t('yii', 'Unable to verify your data submission.')); } return true; } else { return false; } }

    ```

    于是找到错误原因:

    yii 2.0 内,对 CSRF 攻击做了处理,会对 post 提交的数据做 token 验证,而微信 post 到我们服务器的代码中,没有带上这个 token ,所以会验证失败

    解决方法:

    1、在我们的控制器里面,加上这行属性,设置为 false

    public $enableCsrfValidation = false;

    你还可以直接修改顶层控制器的 $enableCsrfValidation ,但是不推荐这样做!

    2、关于如何在单独的action中关闭Csrf验证

    由于Yii2 Controller Csrf验证是在beforeAction中完成的,所以在action中指定
    $this->enableCsrfValidation = false;
    不能实现局部关闭Csrf。

    如何实现

    新建一个Behavior

    <?php
    use Yii;
    use yiibaseActionEvent;
    use yiibaseBehavior;
    use yiiwebController;
    
    
    class NoCsrf extends Behavior
    {
        public $actions = [];
        public $controller;
        public function events()
        {
            return [Controller::EVENT_BEFORE_ACTION => 'beforeAction'];
        }
        public function beforeAction($event)
        {
            $action = $event->action->id;
            if(in_array($action, $this->actions)){
                $this->controller->enableCsrfValidation = false;
            }
        }    
    }

    然后在Controller中添加Behavior

    ?php
    
        public function behaviors()
        {
            return [
                'csrf' => [
                    'class' => NoCsrf::className(),
                    'controller' => $this,
                    'actions' => [
                        'action-name'
                    ]
                ]
            ];
        }

    这样就实现了在action中关闭Csrf而不是在整个Controller中关闭。

  • 相关阅读:
    一周总结
    各个方法的不同和优缺点
    随机抽签程序报告
    一周总结
    一周总结
    一周总结
    数据库基本知识
    线程相关概念
    进程相关概念
    模拟ssh实现远程执行命令(socket)
  • 原文地址:https://www.cnblogs.com/yhdsir/p/5202796.html
Copyright © 2011-2022 走看看