Я разрабатываю приложение 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, я считаю.