2017-06-21 133 views
0

我最近升級到了最新版本的facebook SDK,並且遇到登錄用戶的問題。我生成登錄鏈接就好了,但是當facebook將用戶發回我的站點時與令牌,我得到此錯誤:Facebook SDK錯誤:跨站請求僞造驗證失敗。持久數據中缺少必需的參數「狀態」

fb sdk錯誤:跨站請求僞造驗證失敗。持久數據中缺少必需的參數「狀態」。

我試圖做一些故障排除。我打印出會話數據中的所有內容以及GET請求中的所有內容。我看到GET有一個狀態參數,會話數據有一個FBRLH_state參數。它們都具有相同的價值。那麼它如何告訴我該參數缺失?

我試過一些我在其他問題上看到的建議(即開始會話),但似乎沒有任何工作。

任何幫助將不勝感激!我正在使用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 Facebook\Facebook(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(Facebook\Exceptions\FacebookResponseException $e) { 
       // When Graph returns an error 
       $this->log[] = $this->errors[] = 'fb api error: ' . $e->getMessage(); 
       return null; 
      } catch(Facebook\Exceptions\FacebookSDKException $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 Facebook\FacebookResponse 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(Facebook\Exceptions\FacebookResponseException $e) { 
         // When Graph returns an error 
         $this->api_error = 'fb api error: ' . $e->getMessage(); 
         $this->errors[] = $this->api_error; 
         return null; 
        } 
        catch(Facebook\Exceptions\FacebookSDKException $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['[email protected]_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); 
+0

我想這可能與你正在經歷getRedirectLoginHelper和$ helper-> getAccessToken()的例程兩次有一些奇怪的原因... – CBroe

+0

@CBroe謝謝!那就是訣竅。如果您將其作爲答案提交,我會將其標記爲正確。 – user2874270

回答

1

fb sdk error: Cross-site request forgery validation failed. Required param "state" missing from persistent data.

它是與你通過日常會調用getRedirectLoginHelper和$ helper-> getAccessToken()兩次 - 一次「靠自己」,和然後再次在一個try-catch塊(複製&粘貼錯誤,或不幸的調試嘗試可能?)

我有點懶得去檢查SDK源,但我認爲它故意取消設置狀態參數在代碼交換爲令牌之後的會話內部,作爲使整個過程更安全的一部分 - 以便在調用getA時ccessToken第二次,它失敗。

+0

我必須得到相同的錯誤,並且不要像「getAccessToken」一樣檢查重複的代碼。你能幫我麼。我的演示網址是http://demo.sigzen.net/fb-login/v5/ –

0

這可能有點晚,但我希望它可以幫助別人。

我有這個問題一段時間,我搜索了很多不同的解決方案,其中許多都禁用了CSRF檢查。所以在我讀過的所有東西之後,這對我來說是有效的。

據我所知,當您的重定向網址與您在應用設置中設置的網址不匹配時出現此錯誤,所以我的問題每次都很容易修復,但我也看到人們因沒有會話而出現問題開始正確,所以我會涵蓋這兩個問題。

第1步:確保您的會話在需要時開始。

例如:FB-config.php文件

session_start(); 
include_once 'path/to/Facebook/autoload.php'; 

$fb = new \Facebook\Facebook([ 
    'app_id' => 'your_app_id', 
    'app_secret' => 'your_secret_app_id', 
    'default_graph_version' => 'v2.10' 
]); 

$helper = $fb->getRedirectLoginHelper(); 

如果你的Facebook回調代碼是從配置其他文件放在一邊,然後開始在該文件中的會話了。

例如:FB-callback.php

session_start(); 
include_once 'path/to/fb-config.php'; 

try { 
    $accessToken = $helper->getAccessToken(); 
} catch (\Facebook\Exceptions\FacebookResponseException $e) { 
    echo "Response Exception: " . $e->getMessage(); 
    exit(); 
} catch (\Facebook\Exceptions\FacebookSDKException $e) { 
    echo "SDK Exception: " . $e->getMessage(); 
    exit(); 
} 

/** THE REST OF YOUR CALLBACK CODE **/ 

現在,解決我的實際問題。

第3步:在您的應用程序設置中設置您的重定向URL。

在你的Facebook登錄的應用程序設置,轉到有效的OAuth重定向,你應該已經添加指向你的FB-callback.php文件的URL的URI

http://example.com/fb-callback.php 

AND ALSO 

http://www.example.com/fb-callback.php 

然後設置您的重定向網址如下。

$redirectURL = "http://".$_SERVER['SERVER_NAME']."/fb-callback.php"; 
$permissions = ['email']; 
$fLoginURL = $helper->getLoginUrl($redirectURL, $permissions); 

爲什麼無論有沒有www和爲什麼使用SERVER_NAME?

因爲你有效的OAuth重定向URI需要在你的代碼符合您重定向URL,如果在你的應用程序設置,只設置了您的OAuth重定向爲http://example.com/fb-callback.php並設置$的redirectUrl爲http://example.com/fb-bacllback.php使其匹配,但用戶輸入您的網站作爲http://www.example.com然後用戶將得到Facebook SDK錯誤:跨站請求僞造驗證失敗。持久數據中缺少必需的參數「狀態」,因爲用戶所在的URL不完全符合您的設置。爲什麼?我沒有任何想法。

我的方法使得如果用戶以http://example.comhttp://www.example.com的身份輸入您的網站,它將始終與您在應用設置中設置的內容相匹配。爲什麼?因爲根據用戶在瀏覽器中輸入url的方式,$ _SERVER ['SERVER_NAME']將返回包含或不包含www的域。

這是我的發現,這是關於唯一的工作,我沒有刪除CSRF檢查,迄今沒有問題。

我希望這會有所幫助。

相關問題