无法使用 android 的 asmack 库登录 google talk

Posted

技术标签:

【中文标题】无法使用 android 的 asmack 库登录 google talk【英文标题】:Unable to login to google talk using asmack library for android 【发布时间】:2014-09-15 11:15:22 【问题描述】:

我一直在尝试使用 asmack 库登录 google talk,但没有成功。我真的不知道幕后发生了什么,只是从这里和那里收集了一些代码 sn-ps。这是我目前的 android 活动:

public class MainActivity extends Activity                                                           

    public static final String HOST = "talk.google.com";                                              
    public static final int PORT = 5222;                                                              
    public static final String SERVICE = "gmail.com";                                                 
    public static final String USER = "user@gmail.com"; 
    public static final String PASSWORD = "password"; 

    @Override                                                                                         
    public void onCreate(Bundle savedInstanceState)                                                  
        super.onCreate(savedInstanceState);                                                           
        setContentView(R.layout.main);                                                                
        Context context = getApplicationContext();                                                    
        SmackAndroid asmk = SmackAndroid.init(context);                                               
        SASLAuthentication.registerSASLMechanism("X-OAUTH2", SASLGoogleOAuth2Mechanism.class);        
        SASLAuthentication.supportSASLMechanism("X-OAUTH2", 0);                                       
        ConnectionConfiguration connConfig = new ConnectionConfiguration(HOST, PORT, SERVICE);        
        connConfig.setSecurityMode(SecurityMode.enabled);                                             
        connConfig.setReconnectionAllowed(true);                                                      

        XMPPTCPConnection connection = new XMPPTCPConnection(connConfig);                             
        try                                                                                          
            connection.connect();                                                                     
            try                                                                                      
                connection.login(USER, PASSWORD);                         
             catch (XMPPException ex)                                                               
                Log.w("XMPPChatDemoActivity", "Failed to log in");                                    
                Log.w("XMPPChatDemoActivity", ex.getMessage());                 
                                                                                                     
         catch (...)                                                                   
           ...
        
    

这就是 SASL 机制:

public class SASLGoogleOAuth2Mechanism extends SASLMechanism 

    private static final Logger log = Logger.getLogger("XMPPChatDemoActivity");
    public static final String NAME = "X-OAUTH2";

    public SASLGoogleOAuth2Mechanism(SASLAuthentication saslAuthentication) 
        super(saslAuthentication);
        log.info("Creating SASL mechanism for GTalk (X-OAUTH2)");
    

    @Override
    public void authenticate(String username, String host, String serviceName, String password) throws IOException, SaslException, NotConnectedException 
        this.authenticationId = username;
        this.hostname = host;
        this.password = password;

        String[] mechanisms =  "PLAIN" ;
        Map<String, String> props = new HashMap<String, String>();
        this.sc = Sasl.createSaslClient(mechanisms, username, "xmpp", host, props, this);
        log.info("sc " + sc);
        authenticate();
    

    @Override
    public void authenticate(String host, CallbackHandler cbh) throws IOException, SaslException, NotConnectedException 
        String[] mechanisms =  "PLAIN" ;
        Map<String, String> props = new HashMap<String, String>();

        sc = Sasl.createSaslClient(mechanisms, null, "xmpp", host, props, cbh);
        authenticate();
    
    @Override
    protected void authenticate() throws IOException, SaslException, NotConnectedException 
        String authenticationText = null;

        try  
            if (sc.hasInitialResponse()) 
                byte[] response = sc.evaluateChallenge(new byte[0]);
                authenticationText = Base64.encodeBytes(response, Base64.DONT_BREAK_LINES);
            
         catch (SaslException e) 
            throw new SaslException("SASL authentication failed", e);
        

        // Send the authentication to the server
        getSASLAuthentication().send(new GoogleOAuthMechanism(authenticationText));
    
    @Override
    protected String getName() 
        return NAME;
    
    /**
     * Initiating SASL authentication by select a mechanism.
     */
    public static class GoogleOAuthMechanism extends Packet 
        private final String authenticationText;

        /**
         * Create a GoogleOAuthMechanism.
         *
         * @param authenticationText the authentification token
         *
         */
        public GoogleOAuthMechanism(final String authenticationText) 
            this.authenticationText = authenticationText;
        

        @Override
        public String toXML() 

            StringBuilder stanza = new StringBuilder();
            stanza.append("<auth mechanism=\"").append(NAME);
            stanza.append("\" xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" "
                    + "auth:service=\"oauth2\" "
                    + "xmlns:auth=\"http://www.google.com/talk/protocol/auth\">");
            if (authenticationText != null
                    && authenticationText.trim().length() > 0) 
                stanza.append(authenticationText);
            
            stanza.append("</auth>");
            return stanza.toString();
        
    

代码没问题,我没有收到任何异常,但我收到了&lt;not-authorized&gt; 响应。用户名和密码正确。我找不到该库的任何参考代码。任何帮助将不胜感激。

【问题讨论】:

【参考方案1】:

经过几天的努力并尝试了我在互联网上找到的所有可以想象到的 sn-ps 组合,我发现了一个我很高兴与社区分享的解决方案。

看来,我们应该使用 来自 google 的身份验证令牌,而不是将密码传递给 XMPPTCPConnection.login() 方法。我发现a post 解释了一种生成此类令牌的方法。我的similar question 存在,但它也使用X-GOOGLE-TOKEN 机制进行身份验证,这是我使用X-OAUTH2 机制进行身份验证的另一种方法。此外,我能找到的与使用 OAUTH2 对 google talk 进行身份验证问题相关的所有其他帖子都是旧的。我正在使用 smack 4.0.4 的 asmack 版本。

所以问题中显示的代码工作所需的唯一修改是:

AccountManager am = AccountManager.get(this);
Account accounts[] = am.getAccountsByType("com.google");
conn.login(USER, amf.blockingGetAuthToken(accounts[0], GOOGLE_TOKEN_TYPE, true));

如您所见,我使用存储在设备上的帐户来证明解决方案,但您可以通过其他方式生成令牌,正如我上面评论的那样。

最后,当我通过反复试验找到解决方案时,如果有人解释实际发生的事情或我可能提供的任何错误信息,我将不胜感激,因此可以进一步改进此答案。

【讨论】:

以上是关于无法使用 android 的 asmack 库登录 google talk的主要内容,如果未能解决你的问题,请参考以下文章

无法在 Android 设备上使用 asmack 15 登录 Google Talk

Android Asmack xmpp 登录仅适用于我自己的 Facebook 帐户

Asmack/Openfire 401 错误

无法使用 asmack 获得加入的聊天室

用于 Facebook 聊天的 Asmack 不适用于 PrivacyListManager

roster.getEntities() 总是返回 null aSmack android