Как мне обновить Facebook user_access_token, если я имею дело с большим количеством AJAX? - PullRequest
7 голосов
/ 19 февраля 2012

Пожалуйста, скажите мне, правильно ли я понимаю. (потому что я не могу быть.)

  1. Пользователь что-то публикует на моем сайте. (Он проверил "также публиковать в Facebook".)
  2. Клиент отправляет запрос AJAX POST на мой сервер, и мой сервер вставляет запись в мою базу данных.
  3. Сервер понимает, что срок действия маркера доступа пользователя facebook истек, поэтому отправляет ответ клиенту, сохраняя сообщение в сеансе.
  4. Клиент делает window.location.replace(facebook_oauth_dialog_url)
  5. Тогда пользователь увидит внезапную «вспышку», зайдя на Facebook, затем вернувшись на сайт. Мой сервер получает новый токен доступа.
  6. Мой сервер проверяет сеанс, чтобы увидеть, что следует публиковать в Facebook. Затем он использует новый токен доступа, чтобы опубликовать его в Facebook.

Неужели это так утомительно? Почему я не могу обновить серверную часть приложения без прохождения пользователем диалогового окна?

Весь мой сайт - Backbone.js. Это означает, что это одна большая страница. Я не могу перемещать пользователя назад и вперед между Facebook и моим сайтом вот так.

Ответы [ 7 ]

8 голосов
/ 22 февраля 2012

Идея состоит в том, чтобы использовать Facebook JS-SDK методы:

  1. Пользователь проверяет Опубликовать в Facebook опция
  2. вы проверяете, подключен ли текущий пользователь к вашему приложению (используя FB.getLoginStatus())
  3. если пользователь подключен, у вас есть два варианта:
    • отправлять сообщения напрямую, используя метод FB.api или
    • Отправьте access_token на ваш сервер, чтобы завершить там процесс публикации
  4. если пользователь не подключен (или не вошел в Facebook), используйте метод FB.login()

Вот краткий пример (с Live Demo !) Для начала работы:

<!DOCTYPE html>
<html xmlns:fb="http://www.facebook.com/2008/fbml">
<body>
<div id="fb-root"></div>
<script>
var fbLoaded = false;
window.fbAsyncInit = function() {
    FB.init({
      appId      : 'YOUR_APP_ID', // App ID
      //channelUrl : '//WWW.YOUR_DOMAIN.COM/channel.html', // Channel File
      status     : true, // check login status
      cookie     : true, // enable cookies to allow the server to access the session
      xfbml      : true  // parse XFBML
    });
    fbLoaded = true;
    // Additional initialization code here

};

function postForm() {
    var msg = document.myForm.msg.value;
    // do form validation here, e.g:
    if(!msg.length) {
        alert("You should enter a message!");
        return false;
    }

    // do we need to post to Facebook?
    if(document.myForm.toFB.checked) {
        // is the library loaded?
        if(!fbLoaded) {
            alert("Facebook JS-SDK is not yet loaded. Please try again later or uncheck Post To Facebook option");
            return false;
        }

        FB.getLoginStatus(function(response) {
            if (response.status === 'connected') {
                var uid = response.authResponse.userID;
                var accessToken = response.authResponse.accessToken;
                /* 
                *  message can be posted to Facebook directly
                *  using the FB.api method or accessToken
                *  can be sent to the server and do the call
                *  from there
                */
                myAjaxCall(msg, accessToken);
            } else {
                // status is either not_authorized or unknown
                FB.login(function(response) {
                    if (response.authResponse) {
                        var accessToken = response.authResponse.accessToken;
                        myAjaxCall(msg, accessToken);
                    } else {
                        alert('User cancelled login or did not fully authorize.');
                    }
                }, {scope: 'publish_stream'});
            }
        });
    } else {
        myAjaxCall(msg);
    }
    return false;
}

function myAjaxCall(m,a) {
    alert("Here you make the ajax call\nMessage: " + m + "\nAccess Token: " + a);
}

  // Load the SDK Asynchronously
  (function(d){
     var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
     if (d.getElementById(id)) {return;}
     js = d.createElement('script'); js.id = id; js.async = true;
     js.src = "//connect.facebook.net/en_US/all.js";
     ref.parentNode.insertBefore(js, ref);
   }(document));
</script>

<form id="myForm" name="myForm" action="post" onSubmit="return postForm()">
<p><label>Your Message:</label><br/><textarea name="msg"></textarea></p>
<p><label>Post to Facebook?</label><input type="checkbox" value="1" name="toFB" /></p>
<p><input type="submit" value="Submit"></p>
</form>
</body>
</html>
2 голосов
/ 24 февраля 2012

UPDATE

хорошо, вы делаете что-то не так, вам не нужно обновлять токен доступа, даже если срок его действия истек, все, что вам нужно, это отправить идентификатор пользователя Facebook и контент, который вы хотите опубликовать вместе, на ваш сервер с помощью ajax, а затем опубликовать его без токена доступа. здесь

Публикация потока из приложения - для не авторизованного пользователя, использующего Graph API, php SDK

если у вас есть разрешение publish_stream, вам не нужен токен доступа это документация для publish_stream https://developers.facebook.com/docs/reference/api/permissions/

Позволяет вашему приложению публиковать контент, комментарии и лайки для пользователя. поток и в потоки друзей пользователя. С этим разрешением вы можете публиковать контент в фиде пользователя в любое время, без требующий offline_access. Тем не менее, обратите внимание, что Facebook рекомендует инициируемую пользователем модель совместного использования.

2 голосов
/ 22 февраля 2012

Надеюсь, вы знаете, что если у вас есть разрешение publish_stream, вам не нужен токен доступа. Вот документация для publish_stream и Ниже приведено решение для четырех сценариев

1. Срок действия токена истекает по истечении времени (по умолчанию 2 часа).
2. Пользователь изменяет свой пароль, который делает недействительным токен доступа.
3. Пользователь отменяет авторизацию вашего приложения..
4.Пользователь выходит из Facebook.

Чтобы обеспечить максимальное удобство для ваших пользователей, ваше приложение должно быть готово к обнаружению ошибок для указанных выше сценариев.В следующем PHP-коде показано, как обрабатывать эти ошибки и получать новый токен доступа.

Когда вы перенаправляете пользователя в диалоговое окно авторизации, у пользователя не запрашиваются разрешения, если пользователь уже авторизовал ваше приложение.Facebook вернет вам действительный токен доступа без диалога с пользователем.Однако, если пользователь отменил авторизацию вашего приложения, ему необходимо будет повторно авторизовать ваше приложение, чтобы вы получили access_token.

<?php
$app_id = "YOUR_APP_ID";
$app_secret = "YOUR_APP_SECRET"; 
$my_url = "YOUR_POST_LOGIN_URL";

// known valid access token stored in a database 
$access_token = "YOUR_STORED_ACCESS_TOKEN";

$code = $_REQUEST["code"];

// If we get a code, it means that we have re-authed the user 
//and can get a valid access_token. 
if (isset($code)) {
$token_url="https://graph.facebook.com/oauth/access_token?client_id="
  . $app_id . "&redirect_uri=" . urlencode($my_url) 
  . "&client_secret=" . $app_secret 
  . "&code=" . $code . "&display=popup";
$response = file_get_contents($token_url);
$params = null;
parse_str($response, $params);
$access_token = $params['access_token'];
}


// Attempt to query the graph:
$graph_url = "https://graph.facebook.com/me?"
. "access_token=" . $access_token;
$response = curl_get_file_contents($graph_url);
$decoded_response = json_decode($response);

//Check for errors 
if ($decoded_response->error) {
// check to see if this is an oAuth error:
if ($decoded_response->error->type== "OAuthException") {
  // Retrieving a valid access token. 
  $dialog_url= "https://www.facebook.com/dialog/oauth?"
    . "client_id=" . $app_id 
    . "&redirect_uri=" . urlencode($my_url);
  echo("<script> top.location.href='" . $dialog_url 
  . "'</script>");
}
else {
  echo "other error has happened";
}
} 
else {
// success
echo("success" . $decoded_response->name);
echo($access_token);
}

// note this wrapper function exists in order to circumvent PHP’s 
//strict obeying of HTTP error codes.  In this case, Facebook 
//returns error code 400 which PHP obeys and wipes out 
//the response.
function curl_get_file_contents($URL) {
$c = curl_init();
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($c, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($c, CURLOPT_URL, $URL);
$contents = curl_exec($c);
$err  = curl_getinfo($c,CURLINFO_HTTP_CODE);
curl_close($c);
if ($contents) return $contents;
else return FALSE;
}
?>

для получения более подробной информации вы можете посетить эту ссылку
Спасибо

2 голосов
/ 22 февраля 2012

Перед отправкой на сервер, наберите FB.getLoginStatus() на клиенте, чтобы получить последний токен доступа. При использовании этого метода отсутствует флэш-память и взаимодействие с пользователем, поскольку он просто получает новый токен доступа.

FB.getLoginStatus( function ( response ) {
    if ( response.authResponse ) { 
        var accessToken = response.authResponse.accessToken;
        //post to server
    };
} );
0 голосов
/ 25 февраля 2012

Как сказал @ThinkingStiff, ключевой момент заключается в том, что вам нужно вызвать FB.getLoginStatus () на клиенте, чтобы получить последний токен доступа

В наши дни все крутые детиобрабатывают свои логины и получают токены доступа через JavaScript с помощью SDK.И почему бы и нет?Пользователям это нравится!

После того, как SDK JavaScript получит токен доступа, все AJAX-запросы к вашему серверу также будут иметь доступ к этому токену доступа.То есть он автоматически передается вместе с каждым AJAX-запросом в форме файла cookie.

Таким образом, на стороне сервера вы можете получить токен доступа с помощью файлов cookie (у нашего друга StackOverflow есть несколько ответов, связанных с поискомэто печенье).Однако, если вы сделаете другую классную вещь и будете использовать PHP SDK, вам даже не нужно будет об этом думать, потому что он автоматически захватит для вас cookie, если он там есть!

0 голосов
/ 22 февраля 2012

Вы не можете просто выполнить обмен на стороне сервера, потому что это обходит контроль пользователя над авторизацией.

Как уже говорили другие, вы должны использовать javascript sdk для облегчения обновления токена доступа.По умолчанию он использует iframe и использует всплывающее окно для связи с Facebook.Это должно хорошо работать с вашим приложением backbone.js.

Я хотел бы определить функцию javascript, которая принимает успешно и запрещает обратные вызовы для выполнения после проверки статуса авторизации facebook:

function checkFBAuth(success, denied, scope) {
    FB.getLoginStatus(function (response) {
        if (response.status === 'connected') {
            success(response);
        } else {
            FB.login(function(response) {
                if (response.status === 'connected') {
                    success(response);
                } else {
                    denied(response);
                }
            }, scope);
        } 
    });
};

Это будетпродолжайте и запустите FB.login, если сеанс пользователя истек.При успешном обратном вызове вы также можете передать response.authResponse.signedRequest в качестве подписанного запроса в ваших данных AJAX POST.Это позволит большинству SDK FB (например, PHP SDK) распознавать и проверять подписанный запрос и устанавливать идентификатор пользователя и маркер доступа.Вы также можете передать все данные response.authResponse с помощью своего POST.У него есть accessToken, userID и expiresIn time.

См. https://developers.facebook.com/docs/reference/javascript/FB.getLoginStatus/ для документов на сайте разработчиков Facebook.

Кроме того, если вы включите автономную миграцию устаревания доступа,Вы можете обменять токен доступа, чтобы продлить срок действия до 60 дней вместо 2 часов по умолчанию.См https://developers.facebook.com/docs/offline-access-deprecation/

0 голосов
/ 22 февраля 2012

У меня проблема в другом проекте.

То, как я справляюсь с этим, заключается в создании скрытого фрейма. В первый раз, когда вам нужно, чтобы пользователь принял привилегию, используйте ваше главное окно для перенаправления. затем, когда вы уверены, что пользователь уже принял привилегию, используйте скрытый iframe для связи с Facebook.

Пользователь не увидит «вспышку», потому что это будет сделано в iframe.

Я сделал это с GWT. Вот код, который я использовал: он связывается с Facebook через iframe и проверяет токен доступа каждые 500 мс, чтобы проверить, действителен ли токен.

Код написан на java (скомпилирован в javascript с использованием gwt).

public class FacebookConnector extends Composite
{
        public static final String                                      ARG_ACCESS_TOKEN_EXPIRES        = "fb_accessTokenExpires";
        public static final String                                      ARG_GAME_FACEBOOK_NAME          = "gameFBName";
        public static final String                                      ARG_GAME_FACEBOOK_ID            = "gameFBId";

        private static FacebookConnectorUiBinder        uiBinder                                        = GWT.create(FacebookConnectorUiBinder.class);

        interface FacebookConnectorUiBinder extends UiBinder<Widget, FacebookConnector>
        {
        }

        private static FacebookConnector        me;

        public static FacebookConnector getInstance()
        {
                if (me == null)
                {
                        me = new FacebookConnector();
                }

                return me;
        }

        @UiField
        IFrameElement   iframe;

        private Date    accessToken;
        private Timer   timer;

        protected FacebookConnector()
        {
                initWidget(uiBinder.createAndBindUi(this));

                if (ArgManager.getArg(ARG_ACCESS_TOKEN_EXPIRES) != null)
                {
                        accessToken = new Date(Long.parseLong(ArgManager.getArg(ARG_ACCESS_TOKEN_EXPIRES)));
                }
        }

        public void checkAccessToken(final AbstractAsyncCallback<Void> callback)
        {
                if (accessToken == null || accessToken.before(new Date()))
                {
                        // send authentication
                        String url = "https://graph.facebook.com/oauth/authorize?client_id="
                                        + ArgManager.getArg(ARG_GAME_FACEBOOK_ID) + "&scope=user_birthday,email&redirect_uri="
                                        + ArgManager.getArg(ArgManager.ARG_URL_FACEBOOK_BASE) + "page/facebook-step2%3FgameName%3D"
                                        + ArgManager.getGameShortcut();

                        iframe.setSrc(url);

                        // check url
                        timer = new Timer() {

                                @Override
                                public void run()
                                {
                                        ClientFactory.getInstance().getService().getAccessTokenExpires(new AbstractAsyncCallback<Date>() {

                                                @Override
                                                public void onSuccess(Date result)
                                                {
                                                        super.onSuccess(result);

                                                        if (result != null && result.after(new Date()))
                                                        {
                                                                accessToken = result;

                                                                // call the callback
                                                                callback.onSuccess(null);
                                                        }
                                                        else
                                                        {
                                                                // try again in one second
                                                                timer.schedule(1000);
                                                        }

                                                }

                                        });

                                }
                        };

                        // launch timer in 500 milliseconds
                        timer.schedule(500);
                }
                else
                {
                        callback.onSuccess(null);
                }
        }
}

Надеюсь, это поможет вам.

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