Интеграция чата Facebook
Я написал программу для интеграции чата пользователя Facebook в C#, но всегда получаю <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 Аутентификация чата в C# и X-FACEBOOK-PLATFORM, и мой тип приложения - Native/Desktop.
Кто-нибудь может указать мне правильное направление?
Изменить: Я думаю, что проблема при создании подписи, есть ли способ проверить созданную подпись?
Редактировать 1: Согласно этому SO-ответу токен доступа содержит ключ сеанса после первого | персонаж, и я мог бы найти | персонаж до 2 дней назад, но сейчас я не могу найти | символ в маркере доступа, это действительно странно, так как мне найти ключ сеанса сейчас? (Или, может быть, я должен идти спать сейчас.)
Редактировать 2: Странно, что я всегда получал токен доступа в виде <appId>|<sessionKey>|<digest>
для родного / настольного приложения. Я продолжил поиск и обнаружил, что ключ сеанса необходимо извлечь из устаревшего API- интерфейса auth.promoteSession и кодировать параметры, используя HttpUtility.UrlEncode
вместо HttpUtility.HtmlEncode
,
Теперь я жестко закодировал токен доступа (проверил его в отладчике доступа), ключ сеанса, ключ приложения и секрет приложения, но я получаю ту же ошибку <failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><not-authorized/></failure>
Редактировать 3: Я бился головой в течение недели, и все же это не работает, но сегодня я нашел обновление в документации, которая говорит Note that this needs to be over TLS (Transport Layer Security) or you'll get an error.
Я думаю, мне нужно изменить свой код соответственно.
Изменить 4: я опробовал код в документации и обнаружил, что значение $SESSION_XML
должно быть
$SESSION_XML = '<iq type="set" id="4">'.
'<session xmlns="urn:ietf:params:xml:ns:xmpp-session"/></iq>';
Я опубликую код C#, как только закончу его преобразование.
5 ответов
Чтобы использовать X-FACEBOOK-PLATFORM, вам понадобится сеанс пользователя, который предоставляется устаревшим потоком аутентификации. Однако access_token содержит сеанс пользователя после | как вы отметили в своем edit1.
Мы объявили в последнем сообщении в блоге, что access_token будет зашифрован, и это будет обязательно с 1 октября. До тех пор эту опцию можно переключать в настройках расширенных приложений http://developers.facebook.com/blog/post/553/.
Продвигаясь вперед, access_token сможет использоваться для X-FACEBOOK-PLATFORM.
Вы станете еще быстрее, если начнете с существующей библиотеки XMPP. Вот список: http://xmpp.org/xmpp-software/libraries/
Например, вам захочется, чтобы вы не написали вручную весь свой XML вместо того, чтобы очень скоро прогонять его через DOM. А пока проверьте все ваши входные данные с помощью следующих символов: <>'"&
В Python на сайте разработчиков Facebook есть пример, который может быть полезен: https://developers.facebook.com/docs/chat/
Не знаю, в этом ли проблема, и у меня нет времени на тестирование, но твой сигнал мне не подходит. Также не стоит забывать, что в начале сентября Facebook перешел на OAuth 2.0, поэтому убедитесь, что ваш access_token правильный.
Попробуй это:
string sig = "api_key=" + appId
+ "call_id=" + callId
+ "method=" + method
+ "nonce=" + nonce
+ "session_key=" + SessionKey
+ "v=1.0"
+ APP_SECRET;
MD5 md = MD5.Create();
var hash = md.ComputeHash(Encoding.UTF8.GetBytes(sig));
sig = hash.Aggregate("", (current, b) => current + b.ToString("x2"));
var response = "api_key=" + appId
+ "&call_id=" + callId
+ "&method=" + method
+ "&nonce=" + nonce
+ "&session_key=" + SessionKey
+ "&v=1.0";
// response & signature
response = string.Concat(Uri.EscapeDataString(response),
"&", Uri.EscapeDataString(sig))
// base64 encode
var myEncodedResponseToSend = Convert.ToBase64String(
ASCIIEncoding.ASCII.GetBytes(response));
У меня была такая же проблема, прежде чем пытаться аутентифицироваться с помощью X-FACEBOOK-PLATFORM. Я нашел решение, которое, я думаю, может вам помочь.
XMPP с библиотекой Java Asmack, поддерживающей X-FACEBOOK-PLATFORM
Хотя код является Java, легко понять, как он работает. Хитрость заключается в том, чтобы получить секретный ключ сеанса из Facebook, используя свой токен OAuth 2.0. Вы должны использовать устаревший метод с именем auth.promoteSession следующим образом:
https://api.facebook.com/method/auth.promoteSession?access_token=yourAccessToken
Затем Facebook предоставляет вам секретный ключ сеанса, который вы должны использовать в качестве параметра секретного ключа приложения. Чтобы использовать этот метод, вы должны отключить параметр " Удалить устаревшие API" на этой странице в разделе настроек редактирования и вкладке "Дополнительно".
Я надеюсь, это поможет вам.