2011-09-09 150 views
8

這個問題是相似的:Authenticate to Google Talk (XMPP, Smack) using an authToken如何使用Smack API通過AccountManager的身份驗證令牌向Google Talk進行身份驗證?

  1. 我有android.accounts.AccountManager類及其方法來獲得谷歌帳戶的身份驗證令牌:

    public AccountManagerFuture<Bundle> getAuthToken (Account account, 
         String authTokenType, Bundle options, Activity activity, 
         AccountManagerCallback<Bundle> callback, Handler handler) 
    
  2. 我知道如何準備XML認證:

    jidAndToken ="\0" + UTF8([email protected]) + "\0" + Auth 
    

    (其中「\ 0」意圖是一個值爲零的單個八位字節)。在最初的SASL AUTH使用此:

    <auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' 
         mechanism='X-GOOGLE-TOKEN'>Base64(jidAndToken)</auth> 
    


但我失敗就像是有人做了Facebook的聊天這裏它的Smack API集成:XMPP with Java Asmack library supporting X-FACEBOOK-PLATFORM

有人能幫助我嗎?

+0

我以前看過這個,但從來沒有真正嘗試過。你介意發佈你的代碼,以便我可以嘗試自己做,也許我會找到一個解決方案。謝謝 – Guillaume

回答

1

我知道這個線程有點老,但我認爲我會幫忙...所以這裏是我的班,似乎與smack連接到使用令牌機制Gtalk工作。如實,我寧願去與oauth2 ..但這似乎工作正常。請確保您的用戶名是一樣 ,它應該工作:

public class GoogleTalkAuthentication extends SASLMechanism 
{ 
    static 
    { 
     SASLAuthentication.registerSASLMechanism("X-GOOGLE-TOKEN", GoogleTalkAuthentication.class); 
     SASLAuthentication.supportSASLMechanism("X-GOOGLE-TOKEN", 0); 
    } 

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

    @Override 
    protected String getName() 
    { 
     return "X-GOOGLE-TOKEN"; 
    } 

    @Override 
    public void authenticate(String username, String host, String password) throws IOException, XMPPException 
    { 
     super.authenticate(username, host, password); 
    } 

    @Override 
    protected void authenticate() throws IOException, XMPPException 
    { 
     String authCode = getAuthCode(authenticationId, 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(Base64.encode(jidAndToken.getBytes("UTF-8"))); 

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

     // Send the authentication to the server 
     getSASLAuthentication().send(stanza.toString()); 
    } 

    public static String getAuthCode(String username, String password) throws IOException 
    { 
     StringBuilder urlToRead = new StringBuilder(); 
     urlToRead.append("https://www.google.com/accounts/ClientLogin?accountType=GOOGLE&service=mail&"); 
     urlToRead.append("Email=" + username + "&"); 
     urlToRead.append("Passwd=" + password); 

     URL url = new URL(urlToRead.toString()); 
     HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 
     conn.setRequestMethod("GET"); 

     BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); 

     try 
     { 
      String line; 
      while ((line = rd.readLine()) != null) 
      { 
       if (line.startsWith("Auth=")) 
        return line.substring(5); 
      } 

      return null; 
     } 
     finally 
     { 
      rd.close(); 
     } 
    } 

    public static void main(String[] args) throws IOException 
    { 
     String username = ""; 
     String password = ""; 

     String authCode = getAuthCode(username, password); 
     String jidAndToken = "\0" + URLEncoder.encode(username, "utf-8") + "\0" + authCode; 

     System.err.println(authCode); 
     System.err.println("Code:" + jidAndToken); 
    } 
} 

好運。

8

Vijay,

您的代碼幫了我很多,謝謝!我在這裏發帖提供我的解決方案,以解決使用AccountManager登錄Google Talk的問題。到目前爲止,我還沒有找到完整的解決方案,但是我已經基於上面的代碼開發了我的代碼並糾正了幾行不起作用的代碼。

解決方案有兩個部分。第一個基於上述想法和代碼。它是創建一個SASLMechanism的子類:

import java.io.IOException; 
import java.net.URLEncoder; 

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

import android.util.Base64; 
import android.util.Log; 

public class GTalkOAuth2 extends SASLMechanism { 
public static final String NAME="X-GOOGLE-TOKEN"; 


public GTalkOAuth2(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>"); 

    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(); 
    } 
    } 
} 

第二部分是它的使用。沒有其他例子給我的大事是,當從AccountManager系統獲取令牌時,令牌類型不是「ah」而是「郵件」。這個想法在實例中與谷歌服務器進行直接通信以獲取令牌,但不是通過AccountManager向其請求。把它們放在一起給你,你需要在你的驅動代碼中進行以下操作。創建一個函數來獲取令牌:

public String getAuthToken(String name) 
{ 
    Context context = getApplicationContext(); 
    Activity activity = this; 
    String retVal = ""; 
    Account account = new Account(name, "com.google"); 
    AccountManagerFuture<Bundle> accFut = AccountManager.get(context).getAuthToken(account, "mail", null, activity, null, null); 
    try 
    { 
     Bundle authTokenBundle = accFut.getResult(); 
     retVal = authTokenBundle.get(AccountManager.KEY_AUTHTOKEN).toString(); 
    } 
    catch (OperationCanceledException e) 
    { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    catch (AuthenticatorException e) 
    { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    catch (IOException e) 
    { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    return retVal; 
} 

然後確保正確的SASL系統將用於以後叫它:

SASLAuthentication.registerSASLMechanism(GTalkOAuth2.NAME, GTalkOAuth2.class); 
SASLAuthentication.supportSASLMechanism(GTalkOAuth2.NAME, 0); 
config.setSASLAuthenticationEnabled(true); 

String saslAuthString = getAuthToken(acct.name); 
connection = new XMPPConnection(config); 
try { 
    connection.connect(); 
    connection.login(name, saslAuthString); 
} catch (XMPPException e) { 
    // Most likely an expired token 
    // Invalidate the token and start over. There are example of this available 
} 

快樂谷歌說話!

+0

我正在使用此代碼,但沒有成功解決我的問題。我仍然沒有得到服務器的迴應。 –