Facebook SDK错误:跨站点请求伪造验证失败。永久数据中缺少必需的参数状态(&Q)

我最近升级到最新版本的Facebook SDK,但我在登录用户时遇到了问题。我很好地生成了登录链接,但当Facebook使用令牌将用户发送回我的站点时,我收到以下错误:

FB SDK错误:跨站点请求伪造验证失败。永久数据中缺少必需的参数"STATE"。

我试着解决了一些问题。我输出了会话数据中的所有内容和GET请求中的所有内容。我看到GET有一个STATE参数,而会话数据有一个FBRLHSTATE参数。它们具有相同的价值。那么它怎么会告诉我参数丢失了呢?

我已经尝试了我在其他问题上看到的一些建议(例如,启动会话),但似乎都不起作用。

如有任何帮助,将不胜感激!我使用的是php-graph-sdk-5.5。我的Facebook连接文件如下

    if(!class_exists('facebook')){
    class facebook{

        private $db = null;
        private $fb = null;
        private $token = null;
        private $DEV = null;
        private $sdk_error = null;
        private $api_error = null;
        private $verbose = false;
        private $graph_user = null;
        private $db_helper = null;
        private $errors = null;

        public function __construct($db,
                                    $fb_id = FB_APP_ID,
                                    $fb_secret = FB_APP_SECRET,
                                    $fb_version = FB_DEFAULT_GRAPH_VERSION){
            if($this->verbose) echo '<pre>';
            if($this->verbose) echo 'starting construction'.PHP_EOL;
            $this->db = $db;
            if(!$this->fb){
                $this->log[] = 'no connect found. building..'.PHP_EOL;

                $this->fb = new FacebookFacebook(array(
                            'app_id' => $fb_id,
                            'app_secret' => $fb_secret,

                            'default_graph_version' => $fb_version));
                if(!$this->fb){
                    die('facebook initialization failure');
                }
                $this->log[] = 'finished building new connection'.PHP_EOL;
            }
        }

        public function get_login_url($callback_uri, $permissions = ['email','user_birthday']){

            global $_DEV,$_config;
            $helper = $this->fb->getRedirectLoginHelper();

            $callback_host = ($_DEV ? $_config['dev_domain'] : $_config['live_domain']);
            $callback_url = 'https://'.$callback_host.$callback_uri;
            return $helper->getLoginUrl($callback_url, $permissions);
        }

        public function catch_token(){
            if($this->token){
                $this->log[] = 'already have token.'.PHP_EOL;

                return $this->token;
            } else if(!$this->fb){
                $this->log[] = $this->error[] = 'no facebook connection in catch token()';

            }

            $this->log[] = 'starting catch token routine.'.PHP_EOL;
            //$_SESSION['state']=$_GET['state'];
            echo '<pre>' . var_export($_SESSION, true) . '</pre>';
                        echo '<BR><BR><pre>' . var_export($_GET, true) . '</pre>';
                $helper = $this->fb->getRedirectLoginHelper();

                $this->token = $helper->getAccessToken();

                $this->log[] = 'caught token: '.$this->token;
                $string_token = $this->token.PHP_EOL;
                //die($string_token);
            try {

                $helper = $this->fb->getRedirectLoginHelper();

                $this->token = $helper->getAccessToken();

                $this->log[] = 'caught token: '.$this->token;
                $string_token = $this->token.PHP_EOL;

                return $this->user_flush();
            } catch(FacebookExceptionsFacebookResponseException $e) {
                // When Graph returns an error
                $this->log[] = $this->errors[] = 'fb api error: ' . $e->getMessage();
                return null;
            } catch(FacebookExceptionsFacebookSDKException $e) {
                // When validation fails or other local issues
                $this->log[] = $this->errors[] = 'fb sdk error: ' . $e->getMessage();
                return null;
            } catch(Exception $e){
                $this->log[] = $this->errors[] = 'unknown error: '.$e->getMessage();
                return null;
            }
        }

        public function get_token(){
            $this->log[] = 'get token called.'.PHP_EOL;
            if($this->token){
                $this->log[] = 'token found in object'.PHP_EOL;
                //echo '<pre>';
                //die(debug_print_backtrace());
                return $this->token;
            } else {
                $this->log[] = $this->errors[] = 'token not found in object.'.PHP_EOL;
                return null;
            }
        }

        public function get_user($override = false){
            $fields = array(
                'first_name',
                'last_name',
                'email',
                'id',
                'picture',
                'birthday',
                'gender',);
            $fields = implode(',',$fields);
            if($this->graph_user === null){
                if($this->fb && $this->get_token()){
                    try {
                      // Returns a FacebookFacebookResponse object
                      $resp_url = '/me?fields='.$fields.'&debug=all';
                      $this->log[] = $resp_url;
                      $response = $this->fb->get($resp_url, $this->get_token());
                      $this->graph_user = $response->getGraphUser();
                      return $this->graph_user;
                    } 
                    catch(FacebookExceptionsFacebookResponseException $e) {
                        // When Graph returns an error
                        $this->api_error = 'fb api error: ' . $e->getMessage();
                        $this->errors[] = $this->api_error;
                        return null;
                    }
                    catch(FacebookExceptionsFacebookSDKException $e) {
                        // When validation fails or other local issues
                        $this->sdk_error = 'fb sdk error: ' . $e->getMessage();
                        $this->errors[] = $this->sdk_error;
                        return null;
                    }
                } else {
                    $this->sdk_error = "get_user(): fb connection or token not set. are you logged in?";
                    $this->errors[] = $this->sdk_error;
                    //echo '<pre>';
                    //debug_print_backtrace();
                    //die('token: '.$this->token);
                    return null;
                }
            } else {
                $this->sdk_error = "get_user(): graph_user already set";
                $this->errors[] = $this->sdk_error;
                return $this->graph_user;
            }

        }

        public function get_user_first_name(){
            return $this->get_user()['first_name'];
        }
        public function get_user_last_name(){
            return $this->get_user()['last_name'];
        }
        public function get_user_id(){
            return $this->get_user()['id'];
        }
        public function get_user_email(){
            return $this->get_user()['email'];
        }
        public function get_user_picture(){
            return $this->get_user()['picture']['url'];
        }
        public function get_user_birthday(){
            return $this->get_user()['birthday'];
        }

        public function user_flush(){
            //this is the command function.
            //  runs the basic functionality of this class
            //  by adding this user to the database if they're not there
            //      and logging them in if they are.
            $this->graph_user = $this->get_user();
            //$this->log['graph_user_at_user_flush'] = $this->graph_user;
            $this->build_user();
            $this->log['GRAPH_USER'] = $this->get_user();
            $this->log['user_input_array@user_flush'] = $this->user_input;
            if($return = $this->user->fb_register()){
                //die(print_r(debug_backtrace(),true));
                //$this->log['success return'] = '. '.$return;
                return $return;
            } else {
                //die('<pre>'.print_r(debug_backtrace(),true));
                $this->log['fb_register_fail'] = array('fb_register() (also login) failed.',$this->user->get_errors());
                return null;
            }
        }

        public function build_user(){

            $this->user_input['first_name'] = $this->get_user_first_name();
            //$this->user_input['last_name'] = $this->get_user_last_name();
            $this->user_input['facebook_id'] = $this->get_user_id();
            $this->user_input['email'] = $this->get_user_email();
            $this->user_input['image_url'] = $this->get_user_picture();
            $this->user_input['birthday'] = $this->get_user_birthday();
            if($this->verbose) 
                print_r($this->user_input);
            $this->user = new user($this->user_input,$this->db);
        }

        public function logout(){
            unset($_SESSION['fb_id']);
            unset($this->token);
            unset($this->fb);
        }

        public function get_errors(){
            return array_unique($this->errors);
        }
        public function get_log(){
            return array_unique($this->log);
        }
    }
}


//finally, create the connection.
if(!isset($fb))
    $fb = new facebook($db);

解决方案

FB SDK错误:跨站点请求伪造验证失败。永久数据中缺少必需的参数"STATE"。

这与您正在经历两次调用getRedirectLoginHelper和$helper->getAccessToken()的例程有关--一次"自己",然后在try-Catch块中再次调用(可能是复制粘贴错误或不幸的调试尝试?)

我现在有点懒得去检查SDK源代码,但我认为它在代码被交换为令牌后故意取消了会话中的状态参数,这是为了使整个过程更安全-这样当您第二次调用getAccessToken时,它就会失败。

相关文章