Как обработать подписанный запрос Facebook для приложений iFrame Canvas? - PullRequest
2 голосов
/ 21 июня 2011

Я разрабатываю приложение iFrame Canvas для Facebook, используя CakePHP, его компонент Auth, плагин WebTechNick Facebook и OAuth для страниц холста (я включил это в настройках приложения Facebook Developer). Я хотел бы, чтобы пользователи могли использовать приложение после добавления его в свой профиль (путем запроса разрешений email и publish_stream), посетив http://apps.facebook.com/myapp/ или в качестве вкладки в своем профиле.

Запрос разрешений не является проблемой. Пользователь перенаправляется на страницу запроса разрешений, а затем перенаправляется на метод обратного вызова, который запрашивает access_token в соответствии с этим учебным пособием .

После этого обратного вызова пользователь перенаправляется обратно на http://apps.facebook.com/myapp/, где отображается его личная страница указателя. Здесь также начинаются проблемы. Как только вышеупомянутый URI загружен, браузер запрашивает повторную отправку формы, это происходит каждый раз, когда я перезагружаю http://apps.facebook.com/myapp/. Это так, потому что Facebook хочет передать параметр (ожидаемый) signed_request, и я интересно что с этим делать. Это не пустая переменная, поэтому мне нужен другой метод проверки или перенаправления, возможно?

Как мне обработать процедуру для параметра signed_request и, что более важно, как избавиться от этого диалогового окна повторной отправки формы?

Некоторые из моих методов могут показаться беспорядком из-за всех экспериментов прошлого дня.

Методы

beforeFilter, login и callback, в моем UserController.php:

  function beforeFilter() {
    parent::beforeFilter();
    if (empty($this->permissions)) {
      $this->Auth->allow('login', 'logout', 'callback');
    }
  }

  function login() {
    $session = $this->facebook->getSession();
    $login_url = 'https://graph.facebook.com/oauth/authorize?client_id=' . FACEBOOK_APP_ID . '&redirect_uri=' . MY_APP_URL . '/users/callback/&type=user_agent&&display=page&scope=' . FACEBOOK_APP_PERMISSIONS;
    if($session){
      try {
        $uid = $facebook_client->getUser();
        $me  = $facebook_client->api('/me', $params);
        print($me);
      } catch (FacebookApiException $e) {
        error_log($e);
      }
        } else {
      $this->set('authorise', true);
      $script = '$(document).ready(function() { facebookRequestPermissions("'.$login_url.'");});';
      $this->set('script', $script);
        }
  }

  function callback() {
    function callFb($url, $params) {
        $ch = curl_init();
        curl_setopt_array($ch, array(
            CURLOPT_URL => $url,
            CURLOPT_POSTFIELDS => http_build_query($params),
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_VERBOSE => true
        ));
        $result = curl_exec($ch);
        curl_close($ch);
        return $result;
    }

    $params=array('client_id'=>FACEBOOK_APP_ID, 'type'=>'client_cred', 'client_secret'=>FACEBOOK_APP_SECRET);
    $url = "https://graph.facebook.com/oauth/access_token";
    $access_token = callFb($url, $params);
    $access_token = substr($access_token, strpos($access_token, "=")+1, strlen($access_token));

    if ($access_token) {
      $this->redirect(FACEBOOK_APP_URL);
    } else {
      echo 'An error has occurred';
    }
  }

JavaScript в методе входа в систему относится к этой функции jQuery, Facebook JavaScript SDK инициализируется в $(document).ready():

function facebookRequestPermissions(login_url) {
  FB.getLoginStatus(function(response) {
    if (response.status !== 'unknown') {
      top.location.href=login_url;
    }
  });
}

Функция JavaScript должна срабатывать только при входе пользователя в систему, если нет, отображается другая целевая страница.

Я использую некоторые методы в общем AppControler:

class AppController extends Controller {
  var $components = array('RequestHandler', 'Session', 'Auth', 'Facebook.Connect');
  var $helpers = array('Form', 'Time','Html','Javascript', 'Session', 'Facebook.Facebook');
  protected $facebook;
  protected $permissions;
  private $user;

  function beforeRender() {
    //Save the username if it isn't already present
    if ((int)$this->Auth->user('id') != '' && (string)$this->Auth->user('username') == '') {
      $data = array('id' => (int)$this->Auth->user('id'), 'username' => (string)$this->user['username']);
      $this->loadModel('User');
      $this->User->save($data);
    }
    if (!empty($this->user) && !empty($this->permissions)) {
      $this->set('currentUser', $this->Auth->user());
    }
  }

  function beforeFilter() {
    $this->Auth->autoRedirect = false;
    $this->Auth->loginAction = array('controller' => 'users', 'action' => 'login');
    $this->Auth->loginRedirect = array('controller' => 'users', 'action' => 'index');
    $this->Auth->logoutRedirect = array('controller' => 'users', 'action' => 'login');
    App::import('Lib', 'Facebook.FB');
    $this->facebook = new FB();
    $this->user = $this->facebook->api('/me');
    $this->permissions = $this->facebook->api('/me/permissions');
  }
}

EDIT: Это только кажется проблемой с Firefox. Chrome не отображает диалоговое окно, но вместо этого выполняет тихое обновление, после которого параметр signed_request, как ни странно, пуст. Это не относится к Firefox, где параметр signed_request остается неизменным после каждого запрашиваемого обновления (если только содержимое iFrame не кэшируется), который кажется бесконечным циклом.

РЕДАКТИРОВАТЬ 2: Все еще боролся с этим, но в итоге я отключил опцию OAuth 2.0 для Canvas в приложении Facebook Developer, которое решило проблему повторной отправки формы. Конечно, это нереальное решение, потому что OAuth 2.0 становится обязательным для приложения Canvas на Facebook, я считаю.

1 Ответ

1 голос
/ 21 июня 2011

Поскольку я не могу протестировать все это, я не уверен, что это правильно, но на первый взгляд ваша функция JavaScript выглядит странно для меня.Похоже, вы всегда перенаправляете на URL-адрес входа, хотя пользователь дал разрешение.

Ссылаясь на Facebook JavaScript SDK , функция должна выглядеть следующим образом:

function facebookRequestPermissions(login_url) {
  FB.getLoginStatus(function(response) {
    if (!response.session) {
      top.location.href=login_url;
    }
  });
}

или, если вы хотите позвонить .status:

if (response.status == 'unknown')

По поводу вашего вопроса относительно signed_request: он используется для получения некоторой информации, посмотрите Аутентификация - Подписанный запрос чтобы увидеть, что именно.Вам не нужен другой метод проверки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...