如何使用 Smack API 通过 AccountManager 的身份验证令牌向 Google Talk 进行身份验证?

2024-05-15

这个问题类似于:使用 authToken 对 Google Talk(XMPP、Smack)进行身份验证 https://stackoverflow.com/questions/6194899/authenticate-to-google-talk-xmpp-smack-using-an-authtoken?answertab=oldest#tab-top

  1. 我有 android.accounts.AccountManager 类及其方法来获取 Google 帐户的身份验证令牌:

    public AccountManagerFuture<Bundle> getAuthToken (Account account,
           String authTokenType, Bundle options, Activity activity,
           AccountManagerCallback<Bundle> callback, Handler handler)
    
  2. 我知道如何准备身份验证 XML:

    jidAndToken ="\0" + UTF8([email protected] /cdn-cgi/l/email-protection) + "\0" + Auth
    

    (其中“\0”旨在表示值为零的单个八位字节)。在初始 SASL 身份验证中使用它:

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

但我未能将其与 Smack API 集成,就像有人在 facebook 聊天中所做的那样:XMPP 带有支持 X-FACEBOOK-PLATFORM 的 Java Asmack 库 https://stackoverflow.com/questions/5317329/xmpp-with-java-asmack-library-supporting-x-facebook-platform

有人能帮我吗?


Vijay,

你的代码对我帮助很大,谢谢!我在这里发帖是为了提供我的解决方案来解决使用AccountManager登录Google talk的问题。到目前为止,我还没有找到完整的解决方案,但我根据上面的代码开发了我的解决方案,并纠正了一些不起作用的行。

解决方案有两个部分。第一个是基于上面的思路和代码。就是创建SASL机制的子类:

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”而是“mail”。这个想法存在于与谷歌服务器直接通信以获取令牌的示例中,但不是从 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
}

快乐谷歌交谈!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 Smack API 通过 AccountManager 的身份验证令牌向 Google Talk 进行身份验证? 的相关文章

随机推荐