簡體   English   中英

如果我處理大量的AJAX,如何更新Facebook user_access_token?

[英]How do I renew a Facebook user_access_token if I deal with a lot of AJAX?

如果我理解正確,請告訴我。 (因為我可能不會。)

  1. 用戶在我的網站上發布內容。 (他檢查了“也發布到Facebook”。)
  2. 客戶端向我的服務器發送AJAX POST請求,我的服務器在我的數據庫中插入記錄。
  3. 服務器意識到facebook用戶訪問令牌已過期,因此它將響應發送回客戶端,同時將帖子存儲在會話中。
  4. 客戶端執行window.location.replace(facebook_oauth_dialog_url)
  5. 然后用戶將看到突然的“閃光”,進入Facebook,然后回到網站。 我的服務器獲取新的訪問令牌。
  6. 我的服務器檢查會話以查看應該發布到Facebook的內容。 然后,它使用新的訪問令牌將其發布到Facebook。

這真的很乏味嗎? 如果沒有用戶通過對話框,為什么我不能更新應用服務器端?

我的整個網站是Backbone.js。 這意味着,這是一個重要的頁面。 我不能像這樣在Facebook和我的網站之間來回跳轉用戶。

我們的想法是利用Facebook JS-SDK方法:

  1. 用戶檢查Post To Facebook選項
  2. 檢查當前用戶是否已連接到您的應用程序(使用FB.getLoginStatus()
  3. 如果用戶已連接,您有兩種選擇:
    • 直接使用FB.api方法發布或
    • access_token發送到您的服務器以完成那里的后期處理
  4. 如果用戶未連接(或未登錄到Facebook),請使用FB.login()方法

這是一個快速示例(使用現場演示 !)供您開始使用:

<!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>

在發布到服務器之前,請在客戶端上調用FB.getLoginStatus()以獲取最新的訪問令牌。 使用此方法時沒有閃存,也沒有用戶交互,因為它只是抓取一個新的訪問令牌。

FB.getLoginStatus( function ( response ) {
    if ( response.authResponse ) { 
        var accessToken = response.authResponse.accessToken;
        //post to server
    };
} );

我希望你知道如果你有publish_stream權限你不需要訪問令牌這里是publish_stream的文檔, 下面是四個場景的解決方案

1.令牌在到期后到期(默認為2小時)。
2.用戶更改他/她的密碼,使訪問令牌無效。
3.用戶取消對您的應用的授權。
4.用戶退出Facebook。

為確保為用戶提供最佳體驗,您的應用需要准備好捕獲上述方案的錯誤。 以下PHP代碼向您展示了如何處理這些錯誤並檢索新的訪問令牌。

將用戶重定向到auth對話框時,如果用戶已經授權您的應用程序,則不會提示用戶輸入權限。 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;
}
?>

有關詳細信息,請訪問此鏈接
謝謝

UPDATE

好吧你做錯了什么你不需要更新訪問令牌,即使它已經過期所有你需要的是發送用戶的臉書ID和內容,你想通過ajax一起發布到你的服務器然后發布它沒有訪問令牌只是在這里檢查

從應用程序發布Stream - 對於未登錄的用戶,使用Graph API,php SDK

如果您有publish_stream權限,則不需要訪問令牌,這是publish_stream的文檔https://developers.facebook.com/docs/reference/api/permissions/

使您的應用能夠將內容,評論和喜歡發布到用戶的信息流和用戶朋友的信息流。 有了此權限,您可以隨時將內容發布到用戶的Feed,而無需offline_access。 但請注意,Facebook建議使用用戶啟動的共享模型。

我在另一個項目中遇到了問題。

我處理它的方法是創建一個隱藏的iframe。 您第一次需要用戶接受該權限時,請使用主窗口進行重定向。 然后,當您確定用戶已經接受了該權限時,請使用隱藏的iframe與Facebook通信。

用戶不會看到“flash”,因為它將在iframe中完成。

我用GWT完成了它。 這是我使用的代碼:它通過iframe與Facebook通信,每隔500ms檢查一次訪問令牌,看看令牌是否有效。

代碼在java中(使用gwt在javascript中編譯)。

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);
                }
        }
}

希望它會對你有所幫助。

您不能簡單地進行服務器端交換,因為它繞過了用戶對授權的控制。

像其他人所說,你應該使用javascript sdk來方便更新訪問令牌。 默認情況下,它使用iframe並返回彈出窗口以處理與Facebook的通信。 這應該適用於你的backbone.js應用程序。

我喜歡定義一個javascript函數,該函數在檢查facebook auth狀態后取消成功並拒絕執行回調:

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 在成功回調中,您還可以在您的AJAX POST數據中將response.authResponse.signedRequest作為signed_request傳遞。 這將允許大多數FB SDK(例如,PHP SDK)識別並驗證簽名請求並設置用戶ID和訪問令牌。 您還可以使用POST傳遞整個response.authResponse數據。 它具有accessToken,userID和expiresIn time。

有關Facebook Developers網站上的文檔,請參閱https://developers.facebook.com/docs/reference/javascript/FB.getLoginStatus/

此外,如果啟用脫機訪問棄用遷移,則可以交換訪問令牌以將到期日期延長至60天而不是默認的2小時。 請參閱https://developers.facebook.com/docs/offline-access-deprecation/

就像@ThinkingStiff所說,關鍵是你需要在客戶端調用FB.getLoginStatus()來獲取最新的訪問令牌

如今,所有酷孩子都在使用SDK處理他們的登錄並通過JavaScript檢索他們的訪問權限。 嘿,為什么不呢? 用戶喜歡它!

在JavaScript SDK檢索訪問令牌之后,對服務器的所有AJAX請求也將有權訪問該訪問令牌。 也就是說,它會以cookie的形式自動傳遞每個AJAX請求。

因此,在服務器端,您可以通過cookie檢索訪問令牌(我們的朋友StackOverflow有一些與查找該cookie相關的答案)。 但是,如果你做了另一件很酷的事情並使用PHP SDK,你甚至不需要再考慮一下,因為它會自動為你抓取cookie,如果有的話!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM