之前寫了新版Facebook C# SDK的介紹,但是是使用Java Script去取得Access Token,在某些情況下很能會因為JS支援性而產生問題,於是還是需要有server side的認證方式取得access token,才比較穩當的在各種情況下都可以取得所需資訊,於是就發了這篇啦。要避開使用Facebook JavaScript SDK,我找了一下,看來就是使用Server-Side Authentication這個方式才有辦法,這個server-side認證方式基本上是走OAuth 2.0的協定去跑,在2010時我已寫過文章"[Facebook] C# SDK Authentication"介紹過,串接方式蠻類似的,所以我就不會在這邊做過多介紹,不過上次沒貼code,這次會貼一下方便大家參考。
1. Redirect the user to the OAuth Dialog
第一步是將網頁轉到下面這個網址
https://www.facebook.com/dialog/oauth並帶下列參數
client_id : 應用程式的App ID。
redirect_uri : 認證後要導回的Url。
scope : 向使用者取得的授權。
state : (非必要)可自行運用的不重複字串。
2. The user is prompted to authorize your application
若使用者尚未授權此APP,或是scope有修改,則會出現下面畫面讓使用者確認。

3. The user is redirected back to your app
使用者授權的話,會向 redirect_uri 丟出下面參數回傳
state : 剛剛傳去的state(如果你有傳)
code : Facebook傳回產生的code
使用者拒絕的話,則會丟這些參數
error_reason=user_denied
error=access_denied
error_description=The+user+denied+your+request.
state : 剛剛傳去的state(如果你有傳)
像是這樣

4. Exchange the code for a user access token
取得code後,再將code連同下列參數丟到這網址去(不是redirect)
https://graph.facebook.com/oauth/access_tokenclient_id : 應用程式的App ID。
redirect_uri : 認證後要導回的Url(需與Step 1 一樣)。
client_secret : 應用程式的App Secret。
code : Facebook傳回產生的code
成功的話,該頁面會生出下列資訊,裡面就是我們所要的access_token與這個token的有效時間expries。

5. Make requests to the Graph API
有Access Token後,就可以去撈facebook上使用者有授權的資訊,如同範例上的連結這樣使用。
https://graph.facebook.com/me?access_token=YOUR_USER_ACCESS_TOKEN
最後就是範例啦,請記得要有Facebook C# SDK才能用
FBTest.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="FBTest.aspx.cs" Inherits="FBTest" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script src='http://www.google.com/jsapi' type='text/javascript'></script>
<script language='javascript' type='text/javascript'> google.load("jquery", "1.7.1");</script>
<script type='text/javascript'>
$(document).ready(function () {
window.fbAsyncInit = function () {
FB.init({
appId: 'YOUR_APP_ID', // App ID
status: true, // check login status
cookie: true, // enable cookies to allow the server to access the session
xfbml: true // parse XFBML
});
};
// Load the SDK Asynchronously
(function (d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/all.js#xfbml=1&appId=YOUR_APP_ID";
fjs.parentNode.insertBefore(js, fjs);
} (document, 'script', 'facebook-jssdk'));
});
</script>
</head>
<body>
<div id="fb-root"></div>
<form id="form1" runat="server">
<div>
<asp:Button ID="Button1" runat="server" Text="Auth" onclick="Button1_Click" />
<div class="fb-login-button" data-show-faces="true" data-width="400" data-max-rows="1"></div>
<asp:Label ID="Label1" runat="server" Text=""></asp:Label>
</div>
</form>
</body>
</html>FBTest.aspx.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Web;
using Facebook;
public partial class FBTest : System.Web.UI.Page
{
#region Props
public string AppId = "YOUR_APP_ID";
public string AppSecret = "YOUR_APP_SECRET";
public string RedirectUri = "http://localhost:45353/WebTest/FBTest.aspx";
public string Scope = "email,publish_stream,user_photos";
public string ReturnCode
{
get
{
return (string.IsNullOrEmpty(Request.QueryString["code"])) ? null : Request.QueryString["code"];
}
}
public string ReturnError
{
get
{
return (string.IsNullOrEmpty(Request.QueryString["error"])) ? null : Request.QueryString["error"];
}
}
public int Stages
{
get
{
if (Session["AuthStage"] != null)
return int.Parse(Session["AuthStage"].ToString());
else
return (int)AuthStage.Initial;
}
set { Session["AuthStage"] = value; }
}
#endregion
protected void Page_Load(object sender, EventArgs e)
{
if(Stages==(int)AuthStage.Initial)
{
if(!string.IsNullOrEmpty(ReturnCode))
{
Stages = (int) AuthStage.GotCode;
Session["AccessToken"] = GetAccessToken();
CallFb();
}
if (!string.IsNullOrEmpty(ReturnError))
{
Stages = (int)AuthStage.GotError;
Label1.Text = "Error when user is redirected back";
}
}
}
protected void Button1_Click(object sender, EventArgs e)
{
Stages = (int) AuthStage.Initial;
string url = "https://www.facebook.com/dialog/oauth?client_id=" + AppId + "&redirect_uri=" + RedirectUri + "&scope="+Scope;
Response.Redirect(url);
}
private void CallFb()
{
if (Session["AccessToken"] != null)
{
var accessToken = Session["AccessToken"].ToString();
var client = new FacebookClient(accessToken);
try
{
dynamic result = client.Get("me", new { fields = "name,id,updated_time,picture" });
string name = result.name;
string id = result.id;
string updatedTime = result.updated_time;
Label1.Text = name + " , " + id + " , " + updatedTime + " , " + result.picture;
}
catch (FacebookOAuthException ex)
{
Session.Remove("AccessToken");
HttpRuntime.Cache.Remove("access_token");
Label1.Text = (ex.Message.IndexOf("OAuthException - #190") > -1) ? "User has not authorized" : "unknow error";
}
}
else
{
var client = new FacebookClient();
dynamic me = client.Get("zuck");
string firstName = me.first_name;
string lastName = me.last_name;
Label1.Text = firstName + " , " + lastName;
}
}
private Dictionary<string, string> GetOauthTokens(string code)
{
Dictionary<string, string> tokens = new Dictionary<string, string>();
string url = string.Format("https://graph.facebook.com/oauth/access_token?client_id={0}&redirect_uri={1}&client_secret={2}&code={3}",AppId, RedirectUri, AppSecret, code);
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
StreamReader reader = new StreamReader(response.GetResponseStream());
string retVal = reader.ReadToEnd();
Label1.Text += retVal;
foreach (string token in retVal.Split('&'))
{
tokens.Add(token.Substring(0, token.IndexOf("=")),
token.Substring(token.IndexOf("=") + 1, token.Length - token.IndexOf("=") - 1));
}
}
return tokens;
}
private string GetAccessToken()
{
if (HttpRuntime.Cache["access_token"] == null)
{
Dictionary<string, string> args = GetOauthTokens(Request.Params["code"]);
HttpRuntime.Cache.Insert("access_token", args["access_token"], null, DateTime.Now.AddMinutes(Convert.ToDouble(args["expires"])), TimeSpan.Zero);
}
return HttpRuntime.Cache["access_token"].ToString();
}
public enum AuthStage
{
Initial,
GotCode,
GotError,
GotAccesstoken
}
}貼出前我有稍微修改一下,應該還是會動啦。

No comments:
Post a Comment