【发布时间】:2011-11-05 12:04:40
【问题描述】:
我用 C# 编写了一个集成 Facebook 用户聊天的程序,但是在将响应发送到服务器后,我总是得到<failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><not-authorized/></failure>。
我已经检查了 API 密钥和应用程序密钥,它们都是正确的。看起来我向服务器传递了一些错误的参数。
这是我的代码。
private void GetDetailsButton_Click(object sender, EventArgs e)
{
TcpClient FacebookClient = new TcpClient();
FacebookClient.Connect("chat.facebook.com", 5222);
NetworkStream myns = FacebookClient.GetStream();
string xml = "<?xml version='1.0'?>" +
"<stream:stream " +
"id='1' " +
"to='chat.facebook.com' " +
"xmlns='jabber:client' " +
"xmlns:stream='http://etherx.jabber.org/streams' " +
"version='1.0' >";
StreamWriter mySw = new StreamWriter(myns);
mySw.WriteLine(xml); //sending initial request
mySw.Flush();
byte[] serverResponseByte = new byte[1024];
int myBytesRead = 0;
StringBuilder myResponseAsSB = new StringBuilder();
//reading response from the server to see the supported authentication methods
do
{
myBytesRead = myns.Read(serverResponseByte, 0, serverResponseByte.Length);
myResponseAsSB.Append(System.Text.Encoding.UTF8.GetString(serverResponseByte, 0, myBytesRead));
} while (myns.DataAvailable);
myResponseAsSB.Clear();
xml = "<auth " +
"xmlns='urn:ietf:params:xml:ns:xmpp-sasl' " +
"mechanism='X-FACEBOOK-PLATFORM' />";
mySw.WriteLine(xml);
mySw.Flush(); //sending response to server to use X-FACEBOOK-PLATFORM
//reading challenge send by the server
do
{
myBytesRead = myns.Read(serverResponseByte, 0, serverResponseByte.Length);
myResponseAsSB.Append(System.Text.Encoding.UTF8.GetString(serverResponseByte, 0, myBytesRead));
} while (myns.DataAvailable);
myResponseAsSB.Replace("<challenge xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">", "");
myResponseAsSB.Replace("</challenge>", "");
//converting challenge string to normal string
byte[] myregularstrigbytes = Convert.FromBase64String(myResponseAsSB.ToString());
string myregularstring = System.Text.Encoding.UTF8.GetString(myregularstrigbytes);
//I've hardcoded the accesstoken here for testing purpose.
string SessionKey = AccessToken.Split('|')[1];
string response = ComposeResponse(myregularstring);
byte[] myResponseByte = Encoding.UTF8.GetBytes(response.ToString());
string myEncodedResponseToSend = Convert.ToBase64String(myResponseByte);
xml = String.Format("<response xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">{0}</response>", myEncodedResponseToSend);
mySw.WriteLine(xml);
mySw.Flush(); //sending the response to the server with my parameters
myResponseAsSB.Clear();
//checking if authentication succeed
do
{
myBytesRead = myns.Read(serverResponseByte, 0, serverResponseByte.Length);
myResponseAsSB.Append(System.Text.Encoding.UTF8.GetString(serverResponseByte, 0, myBytesRead));
} while (myns.DataAvailable);
MessageBox.Show(myResponseAsSB.ToString());
}
private string ComposeResponse(string serverresponse)
{
string version = serverresponse.Split('&')[0].Split('=')[1];
string method = serverresponse.Split('&')[1].Split('=')[1];
string nonce = serverresponse.Split('&')[2].Split('=')[1];
string SessionKey = AccessToken.Split('|')[1];
long callId = (long)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
string sig = "api_key=" + appId
+ "call_id=" + callId
+ "method=" + method
+ "nonce=" + nonce
+ "session_key=" + SessionKey
+ "v=" + "1.0"
+ AppSecret;
MD5 md = MD5.Create();
var hash = md.ComputeHash(Encoding.UTF8.GetBytes(sig));
sig = hash.Aggregate("", (current, b) => current + b.ToString("x2"));
return "api_key=" + HttpUtility.UrlEncode(appId)
+ "&call_id=" + HttpUtility.UrlEncode(callId)
+ "&method=" + HttpUtility.UrlEncode(method)
+ "&nonce=" + HttpUtility.UrlEncode(nonce)
+ "&session_key=" + HttpUtility.UrlEncode(SessionKey)
+ "&v=" + HttpUtility.UrlEncode("1.0")
+ "&sig=" + HttpUtility.UrlEncode(sig);
}
我参考了这篇文章Facebook Chat Authentication in C#和X-FACEBOOK-PLATFORM,我的应用类型是Native/Desktop。
有人能指出我正确的方向吗?
编辑:我认为问题出在创建签名时,有什么方法可以验证创建的签名吗?
编辑1:根据SO answer,访问令牌包含第一个| 之后的会话密钥。字符,我可以找到 |直到 2 天前的字符,但现在我找不到 |访问令牌中的字符,真的很奇怪,那么我现在如何找到会话密钥? (或者我现在应该去睡觉了。)
编辑2:奇怪的是,我总是以<appId>|<sessionKey>|<digest> 的形式获得本机/桌面应用程序的访问令牌。我做了进一步的搜索,发现会话密钥需要从auth.promoteSessionlegacy api中提取并使用HttpUtility.UrlEncode而不是HttpUtility.HtmlEncode对参数进行编码。
现在我已经硬编码了访问令牌(在Access Token Debugger 中验证它)、会话密钥、应用程序密钥和应用程序密钥我仍然收到相同的错误<failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><not-authorized/></failure>
编辑 3: 一个多星期以来,我一直在敲我的脑袋,但仍然无法正常工作,但今天我在 documentation 中发现了一个更新,上面写着 Note that this needs to be over TLS (Transport Layer Security) or you'll get an error. 我想我需要相应地修改我的代码。
Edit 4 :我试过文档中的代码,发现$SESSION_XML的值应该是
$SESSION_XML = '<iq type="set" id="4">'.
'<session xmlns="urn:ietf:params:xml:ns:xmpp-session"/></iq>';
我将在完成转换后发布 C# 代码。
【问题讨论】:
-
OH... 很有趣,你得到了
... 因为这是我目前因为一些奇怪的原因而遇到的错误。感谢我的博客链接! :) -
用户是否授予您的应用程序
xmpp_loginextended permission? -
另外,您确定您的硬编码访问令牌没有过期吗?
-
@Casey 希望我使用的是我自己的帐户并且我已经授予了权限,我什至确保访问令牌没有过期,但它仍然不起作用。
-
其他一些在黑暗中拍摄的照片——如果您拨打
HtmlEncode电话会发生什么?您要散列的参数应该与您传入的参数完全相同。另外,如果您不包含call_id参数会怎样?一年前我在写类似的代码时,没有包含那个参数。
标签: c# facebook xmpp x-facebook-platform