Why is my test application in an endless redirect

2019-03-17 00:00发布

问题:

I am using the PHP SDK Version 3.1.1 in order to make a simple call to the Graph API. I am running it locally at http://local.fb-sandbox. The facebook application settings have the site URL set to http://local.fb-sandbox/.

I am redirected to the facebook login page and then to the page requesting my permission when I go to http://local.fb-sandbox but the application then goes into a redirect loop between a URL like:

http://local.fb-sandbox/?state=e9c091bb61afe08139af4e3b153a1e9e&code=AQBDJ4yMWVOIrukx6nRkxhNbnPH9nX6OvuqOWhVJEAgLkq6Lz27iq_-B6AIAGQ_cOpBIZktCPLLs_G5Hpt8QO5PRhDUN8l-Yu3JuT0YTzwVQiAqBlgutgia60lRT-ZzE3IHguStHq4gtuPQYJh423TBer-mB8BsqERvNsoF1L4NNe90WAWU8--MFAU3Oc4eeXyI#_=_

and

https://www.facebook.com/dialog/oauth?client_id=375741229103324&redirect_uri=http%3A%2F%2Flocal.fb-sandbox%2F%3Fstate%3Dccd13778febb68d3eb1f4763a99b2ace%26code%3DAQBFegtkch4m34-2F9KMKgScrPhWzI0qeKJlvnM6uAD81BYm2xakv0S7DEbUrNwlECrgth5-YHdT8IR_vCBzW29QMh3ecOiiEk7P03wQG2V2gaxAUsMqOOZvTl_Oq3SefiLn9BvBAPQSGXQdRSZBVdsUqDT1aZ430Lcx8Ic6axaHSyHwlkkNK5EjRhYdkjYYz0YmENk64kRf4tvmX4WrH6f4&state=19a3862962dd0422628eb7c28a832380&scope=email%2Cread_stream%2Cpublish_stream%2Cuser_photos%2Cuser_videos&fbconnect=1#_=_

I have a call to session_start() at the top of my script and have tried both with and without it. The PHP cookie is being set fine.

I've seen a lot of similar questions on here regarding this redirection loop but none of the suggested answers resolved it and they are all quite old. Should this work on localhost? AM I missing an application setting in the app settings on Facebook?

UPDATE

So it seems that if you use the code from here: http://developers.facebook.com/docs/authentication/ then it works. The php-sdk example on github completely ignores this and does not include the fact that you need to check whether 'code' is set and generate your own CSRF token. You then need to make a call to grab an access token before being able to make a call to the Graph API.

Also, the SDK's getLoginURL() method returns an https:// URL which doesn't seem to work. If I craft my own URL then it works.

WORKING CODE:

if(empty($code)) {
    $_SESSION['state'] = md5(uniqid(rand(), TRUE));
$login_url_params = array(
      'scope' => 'email,read_stream,publish_stream,user_photos,user_videos',
      'fbconnect' =>  1,
      'redirect_uri' => 'http://local.fb-sandbox/',
'state'=>$_SESSION['state']
   ); //using this array via the sdk does not work

    $dialog_url = "http://www.facebook.com/dialog/oauth?client_id=" 
       . $app_id . "&redirect_uri=" . urlencode($my_url) . "&state="
       . $_SESSION['state']; //this url works

    //var_dump($dialog_url);echo "<br />";
    $login_url = $facebook->getLoginUrl();
    //var_dump($login_url);
    header("Location:{$dialog_url}");//works
    //header("Location:{$login_url}");//does not work
    exit;
}



if($_REQUEST['state'] == $_SESSION['state']) {
 $token_url = "https://graph.facebook.com/oauth/access_token?"
       . "client_id=" . $app_id . "&redirect_uri=" . urlencode($my_url)
       . "&client_secret=" . $app_secret . "&code=" . $code;
$aContext = array(
    'http' => array(
        'proxy' => 'tcp://xxxx0:80',
        'request_fulluri' => true,
    ),
);
$cxContext = stream_context_create($aContext);
      $response = file_get_contents($token_url, FALSE, $cxContext);

      $params = null;
      parse_str($response, $params);

      $graph_url = "https://graph.facebook.com/me?access_token=" . $params['access_token'];

      $user = json_decode(file_get_contents($graph_url, FALSE, $cxContext));
      //var_dump($user);exit;
}

//var_dump($user);exit;
  return $app->render('test.html',array('myvar', $user));
  exit();

Note that I am going through a proxy so have to set a context for the file_get_contents() calls.

If anyone can convert my code to use the proper SDK methods and get it working (bearing in mind that I need it to work behind a proxy) then you'll get the bounty.

回答1:

Many of the various server-side Facebook SDKs do not handle authentication in accordance with the documentation and recommended practices Facebook has shared over the last 3 or 4 months. You found one good example of this in how the PHP SDK uses (or doesn't use) the code parameter. There are other examples such SDKs directly reading the Facebook cookies, something Facebook engineers tell developers they should not do since the cookies are just "an implementation detail" and not something developers outside of Facebook should be building dependencies on.

I am not sure where you got that code in your working code example, but I couldn't find any support for including parameters such as fbconnect=1

So given that the SDK is not implementing authentication as per Facebook recommendations and documentation, and that Facebook has provided a complete PHP implementation in their documentation, I recommend you just use the version Facebook provides, copy and pasted here for your reference from this page http://developers.facebook.com/docs/authentication/ :

     <?php 

       $app_id = "YOUR_APP_ID";
       $app_secret = "YOUR_APP_SECRET";
       $my_url = "YOUR_URL";

       session_start();
       $code = $_REQUEST["code"];

       if(empty($code)) {
         $_SESSION['state'] = md5(uniqid(rand(), TRUE)); //CSRF protection
         $dialog_url = "http://www.facebook.com/dialog/oauth?client_id=" 
           . $app_id . "&redirect_uri=" . urlencode($my_url) . "&state="
           . $_SESSION['state'];

         echo("<script> top.location.href='" . $dialog_url . "'</script>");
       }

       if($_REQUEST['state'] == $_SESSION['state']) {
         $token_url = "https://graph.facebook.com/oauth/access_token?"
           . "client_id=" . $app_id . "&redirect_uri=" . urlencode($my_url)
           . "&client_secret=" . $app_secret . "&code=" . $code;

         $response = @file_get_contents($token_url);
         $params = null;
         parse_str($response, $params);

         $graph_url = "https://graph.facebook.com/me?access_token=" 
           . $params['access_token'];

         $user = json_decode(file_get_contents($graph_url));
         echo("Hello " . $user->name);
       }
       else {
         echo("The state does not match. You may be a victim of CSRF.");
       }

     ?>


回答2:

There are several problems with this.

  1. Your redirect_uri should be like http://local.fb-sandbox/ . There must be a trailing slash at the end - both in the code and the facebook app settings in developers.facebook.com.

  2. You have to user uurlencode on the redirect_uri.

  3. Don't use $_SERVER['REQUEST_URI'] in the redirect_uri. Find a way to add any parameters you need by processing app_data or adding them depending on your user journey.

As a start replace this line:

'redirect_uri' => urlencode('http://local.fb-sandbox/'),

and experiment with adding parameters later.