Интеграция чата Facebook - PullRequest
       27

Интеграция чата Facebook

16 голосов
/ 28 августа 2011

Я написал программу для интеграции чата пользователя 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> для нативного / настольного приложения. Я продолжил поиск и обнаружил, что ключ сеанса необходимо извлечь из auth.promoteSession legacy api и кодировать параметры, используя HttpUtility.UrlEncode вместо HttpUtility.HtmlEncode.

Теперь я жестко запрограммировал токен доступа (проверено в Access Token Debugger ), ключ сеанса, ключ приложения и секрет приложения, но я получаю ту же ошибку <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. I думаю, мне нужно соответствующим образом изменить свой код.

Редактировать 4: Я опробовал код в документации и обнаружил, что значение $SESSION_XML должно быть

$SESSION_XML = '<iq type="set" id="4">'.
  '<session xmlns="urn:ietf:params:xml:ns:xmpp-session"/></iq>';

Я опубликую код C #, как только закончу его преобразование.

Ответы [ 5 ]

12 голосов
/ 06 сентября 2011

Чтобы использовать X-FACEBOOK-PLATFORM, вам потребуется сеанс пользователя, который предоставляется с устаревшим потоком аутентификации. Однако access_token содержит сеанс пользователя после | как вы отметили в своем edit1.

Мы объявили в последнем сообщении в блоге, что access_token будет зашифрован, и это будет обязательно с 1 октября. До тех пор эту опцию можно переключать в дополнительных настройках приложения http://developers.facebook.com/blog/post/553/.

Продвигаясь вперед, access_token сможет использоваться для X-FACEBOOK-PLATFORM.

7 голосов
/ 29 августа 2011

Вы будете быстрее, если начнете с существующей библиотеки XMPP.Вот список: http://xmpp.org/xmpp-software/libraries/

Например, вам захочется, чтобы вы не закодировали вручную весь ваш XML вместо того, чтобы в ближайшее время выполнить его через DOM очень .А пока проверьте все ваши входные данные с помощью следующих символов: <>'"&

5 голосов
/ 29 августа 2011

В Python на сайте разработчика Facebook есть пример, который может пригодиться: https://developers.facebook.com/docs/chat/

1 голос
/ 11 сентября 2011

Не знаю, в этом ли проблема, и у меня нет времени на тестирование, но твой сигнал мне не подходит.Также не стоит забывать, что 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));
1 голос
/ 10 сентября 2011

У меня была такая же проблема, прежде чем пытаться аутентифицироваться с помощью 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 на этой странице в разделе настроек редактирования и на вкладке "Дополнительно".

Я надеюсь, что этопомогает тебе.

...