2013-01-14 46 views
4

我正在編寫一個連接到XMPP服務器的聊天應用程序,如果用戶選擇,我想讓他們選擇連接到他們的Google聊天帳戶,而不必輸入憑證... 我用谷歌的JavaScript API彈出谷歌登錄表單,併成功登錄後訪問令牌將生成。現在使用訪問令牌和用戶電子郵件ID我想與xmpp服務器通信,以便用戶可以與他們的GTalk朋友聊天。使用authToken連接到GTalk服務器(XMPP,Smack)

我搜索了很多,但沒有找到解決方案。無論我發現需要用戶密碼,但我想使用訪問令牌。

SASLAuthentication.registerSASLMechanism("X-OAUTH2", GoogleConnectSASLMechanism.class); 
SASLAuthentication.supportSASLMechanism("X-OAUTH2", 0); 
config = new ConnectionConfiguration(server, 5222, 'gmail.com'); 
config.setSASLAuthenticationEnabled(true); 
config.setSecurityMode(SecurityMode.enabled); 
config.setReconnectionAllowed(true); 

connection = new XMPPConnection(config); 
connection.connect(); 

connection.login(username, session_key, "Chat"); 
setServer(SERVER_TYPE.GTALK); 

GoogleConnectSASLMechanism.java代碼如下: -

package org.jivesoftware.smack; 

    import java.io.IOException; 
    import java.net.URLEncoder; 
    import java.io.UnsupportedEncodingException; 
    import java.security.MessageDigest; 
    import java.security.NoSuchAlgorithmException; 
    import java.util.GregorianCalendar; 
    import java.util.HashMap; 
    import java.util.Map; 

    import javax.security.auth.callback.CallbackHandler; 
    import javax.security.sasl.Sasl; 

    import org.jivesoftware.smack.SASLAuthentication; 
    import org.jivesoftware.smack.XMPPException; 
    import org.jivesoftware.smack.packet.Packet; 
    import org.jivesoftware.smack.sasl.SASLMechanism; 
    import org.jivesoftware.smack.util.Base64; 


    public class GoogleConnectSASLMechanism extends SASLMechanism { 
    public static final String NAME="X-OAUTH2"; 


    public GoogleConnectSASLMechanism(SASLAuthentication saslAuthentication) { 
     super(saslAuthentication); 
    } 

    @Override 
    protected String getName() { 
     return NAME; 
    } 

    static void enable() { } 

    @Override 
    protected void authenticate() throws IOException, XMPPException 
    { 
     String authCode = password; 
     String jidAndToken = "\0" + URLEncoder.encode(authenticationId, "utf-8") + "\0" + authCode; 

     StringBuilder stanza = new StringBuilder(); 
     //stanza.append("<auth mechanism=\"").append(getName()); 
     //stanza.append("\" xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">"); 
     // stanza.append(new String(Base64.encode(jidAndToken.getBytes("UTF-8"), Base64.DEFAULT))); 
     stanza.append("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" mechanism=\"").append(getName()); 
     stanza.append("\" auth:service=\"oauth2\""); 
     stanza.append("\" xmlns:auth=\"http://www.google.com/talk/protocol/auth\">"); 
     stanza.append("\" base64(\"\\0"+user_name+"\\0" + authCode+")"); 



     stanza.append("</auth>"); 

     //Log.v("BlueTalk", "Authentication text is "+stanza); 
     // Send the authentication to the server 
     getSASLAuthentication().send(new Auth2Mechanism(stanza.toString())); 
    } 

    public class Auth2Mechanism extends Packet { 
     String stanza; 
     public Auth2Mechanism(String txt) { 
      stanza = txt; 
     } 
     public String toXML() { 
      return stanza; 
     } 
    } 


    /** 
    * Initiating SASL authentication by select a mechanism. 
    */ 
    public class AuthMechanism extends Packet { 
     final private String name; 
     final private String authenticationText; 

     public AuthMechanism(String name, String authenticationText) { 
      if (name == null) { 
       throw new NullPointerException("SASL mechanism name shouldn't be null."); 
      } 
      this.name = name; 
      this.authenticationText = authenticationText; 
     } 

     public String toXML() { 
      StringBuilder stanza = new StringBuilder(); 
      stanza.append("<auth mechanism=\"").append(name); 
      stanza.append("\" xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">"); 
      if (authenticationText != null && 
        authenticationText.trim().length() > 0) { 
       stanza.append(authenticationText); 
      } 
      stanza.append("</auth>"); 
      return stanza.toString(); 
     } 
     } 
    } 

但我從connection.login()說: 「用戶名或密碼不正確」

要做到這一點得到了一個異常,我會得到使用谷歌帳戶的權限,使用令牌獲取令牌並驗證到Google Talk(XMPP服務器,使用Smack)。

問題是..我該怎麼做T'我的意思是,如果我知道登錄和令牌,我如何驗證GTalk服務器?

任何幫助,將不勝感激... :)

+0

嗨imVJ,我也得到了與上面提到的相同的要求,請指導我如何獲取accesstoken,連接到gtalk服務器以及如何與用戶聊天? – user2709752

回答

3

維傑,

更改您的身份驗證功能如下:

protected void authenticate() throws IOException, XMPPException { 
    final StringBuilder stanza = new StringBuilder(); 
    byte response[] = null; 

    stanza.append("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\"" + 
      "mechanism=\"X-OAUTH2\"" + 
      "auth:service=\"oauth2\"" + 
      "xmlns:auth= \"http://www.google.com/talk/protocol/auth\">"); 

    String composedResponse = "\0" + username + "\0" + sessionKey; 
    response = composedResponse.getBytes("UTF-8"); 
    String authenticationText = ""; 
    if (response != null) { 
     authenticationText = Base64.encodeBytes(response, Base64.DONT_BREAK_LINES); 
    } 

    stanza.append(authenticationText); 
    stanza.append("</auth>"); 

    // Send the authentication to the server 
    Packet p=new Packet() { 
     @Override 
     public String toXML() { 
      return stanza.toString(); 
     } 
    }; 
    getSASLAuthentication().send(p); 
} 

它作爲您的原始身份驗證功能相同。我剛剛改變了節。

+0

它的工作完美。非常感謝Ketan .. !! :) – imVJ

+0

這裏的'username'和'sessionKey'值是什麼。我無法解決這個問題。 –

2

你的問題似乎是與行:

stanza.append("\" base64(\"\\0"+user_name+"\\0" + authCode+")"); 

所以我覺得這是你authenticate功能應該是什麼樣子:

protected void authenticate() throws IOException, XMPPException 
{ 
    String authCode = password; 
    String jidAndToken = "\0" + authenticationId + "\0" + authCode; 

    StringBuilder stanza = new StringBuilder(); 
    stanza.append("<auth mechanism=\"").append(getName()); 
    stanza.append("\" xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">"); 
    stanza.append(new String(Base64.encode(jidAndToken.getBytes("UTF-8"), Base64.DEFAULT))); 
    stanza.append("</auth>"); 

    //Log.v("BlueTalk", "Authentication text is "+stanza); 
    // Send the authentication to the server 
    getSASLAuthentication().send(new Auth2Mechanism(stanza.toString())); 
} 

所以,它更像是你的評論代碼。 base64(..)根本不應出現在<auth>內容中。那裏應該只有一個base64編碼的字符串。

隨着你在我的線上關於同一主題的幫助,我能夠成功登錄。

+0

我認爲這和你原來的評論代碼唯一的區別在於'authenticationId'不是URL編碼。根據我的經驗,它不需要(它畢竟是base64編碼!) – dexy

1

我很欣賞Ketan的回答,它拯救了我的整個項目。我一直在解決這個問題好幾天......無論如何,我希望更多的人能夠從這篇文章中找到他們的解決方案。

我使用Smack 3.4,但我認爲這個答案也適用於以後的版本。

我只是在詳細解釋Ketan的答案,這對我很有用(剛剛註冊的Stack Overflow,無法對原始答案發表評論)。

只需重寫GoogleConnectSASLMechanism類的authenticate()方法(例如在本地創建GoogleConnectSASLMechanism類),而不是使用Smack提供的類。

Google擁有自己的OAUth2機制,具有自定義屬性。這就是Smack中「X-OAUTH2是實驗性」的原因。您可以在Smack的文檔here中找到此聲明。 「自定義屬性」是xml: <auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="X-OAUTH2" auth:service="oauth2" xmlns:auth="http://www.google.com/talk/protocol/auth"> base64("\0" + user_name + "\0" + oauth_token) </auth>

這可以在google's instruction找到。 Smack不適用於X-OAUth2的原因是因爲它的節中沒有包含這段XML。所以,解決方案只是添加它。

相關問題