为什么AccountAuthenticator#getAuthToken()没有被调用?

11

我通过扩展AbstractAccountAuthenticator并实现addAccount()getAuthToken()创建了自己的 Android 帐户验证器。其中一些方法被AccountManager调用,但其他方法不会。

这很好用:

AccountManager#addAccount()

AccountManager accountManager = AccountManager.get(activity);
accountManager.addAccount(MyAccountAuthenticator.ACCOUNT_TYPE,
    MyAccountAuthenticator.AUTHTOKEN_TYPE_FULL_ACCESS, null, null,
    activity, callback, null);

当我在我的Activity中调用AccountManager#getAuthToken()时出现问题。 AccountManager没有调用我在AccountAuthenticator中定义的getAuthToken()方法,而是调用一些默认方法,该方法仅检查authToken的存在性,然后才启动AuthenticatorActivity

这不起作用。 它没有调用我的getAuthToken()方法:

AccountManager#getAuthToken()

AccountManager accountManager = AccountManager.get(activity);
accountManager.getAuthToken(
        mAccount, MyAccountAuthenticator.AUTHTOKEN_TYPE_FULL_ACCESS, null,
        activity, callback, handler);

认证服务

我创建了我的服务并定义了onBind()。否则,addAccount()将无法正常工作。

public IBinder onBind(Intent intent) {
    return intent.getAction().equals(ACTION_AUTHENTICATOR_INTENT) ? new MyAccountAuthenticator(this).getIBinder() : null;
}

编辑:在应用程序获得用户的身份验证令牌之后,我会在MyAuthenticatorActivity中调用addAccountExplicitly

MyAuthenticatorActivity类的片段,扩展自AccountAuthenticatorActivity

if (getIntent().getBooleanExtra(KEY_IS_ADDING_NEW_ACCOUNT, false)) {
    // Creating the account on the device and setting the auth token we recieved
    accountManager.addAccountExplicitly(account, null, null);
}

你在活动中曾经使用过 addAccountExplicitly 吗? - Thorn G
是的,我在我的 AccountAuthenticatorActivity 子类中调用它。我已经将其添加到问题的编辑中。 - Austyn Mahoney
如果调用 getAuthToken 的结果是启动了您的登录活动,则表示正在调用您的验证器 -- Android 没有其他方法来确定要启动的活动,除非您返回一个 Intent。我注意到您正在使用空密码添加帐户。也许如果找到空密码,您的实现会短路?请在您的验证器中发布 getAuthToken 的正文。 - Thorn G
正如我在问题中提到的那样,当存在现有的身份验证令牌时,getAuthToken()甚至不会被调用。它绕过了调用并直接返回身份验证令牌,这不是我期望它做的。根据我的理解文档,它应该仍然调用我的方法。然后我可以决定是否要返回现有的令牌或获取一个新的令牌(在返回令牌之前,我会检查身份验证令牌是否已过期)。 - Austyn Mahoney
密码为空,因为我正在使用OAuth Bearer令牌。不需要设置密码,我从不使用该字段。当实际调用getAuthToken方法时,它非常有效,无需查看源代码。 - Austyn Mahoney
我的回答解决了问题吗? - Thorn G
2个回答

28

您的评论大大澄清了问题 - 如果为帐户设置了授权令牌,则不会调用您的 getAuthToken 方法,直到该令牌失效。通常,您可以在从 Web 服务收到401或403等内容时调用 invalidateAuthToken 来实现这一点。

getAuthToken 方法的Javadoc中可以看出:

  

如果此帐户和类型的先前生成的授权令牌已缓存,则返回该令牌。否则,如果可用保存的密码,则将其发送到服务器以生成新的授权令牌。否则,提示用户输入密码。

由于您的令牌存储在缓存中,因此它会直接返回,而不会调用您的验证器。


2
谢谢。文档对于何时调用验证器以及何时仅调用其自身代码非常模糊。我认为我的验证器应该实现您引用中描述的功能。 - Austyn Mahoney
7
没问题 -- 我同意身份验证器文档通常质量都很差。 - Thorn G
此外,如果 getAuthToken() 成功返回 KEY_AUTHTOKEN 一次,它会自动缓存(即使在您的应用程序中没有调用 AccountManager.setAuthToken())。因此,所有后续对 AccountManager.getAuthToken() 的调用都不会导致调用 Authenticator.getAuthToken(),而只会立即返回字符串令牌。已在 Android 4.3 三星 Note 2 上进行了测试。 - Deepscorn
1
谢谢大家!那么,既然调用getAuthToken()已经能为你完成所有操作了,peekAuthToken()到底有什么作用呢?我在 Authenticator 之外调用 setAuthToken,然后在我的 getAuthToken 中调用 peekAuthToken 来检查我们是否有缓存的 authToken……但它没有被调用,因为getAuthToken已经为你完成了这项工作,对吧? - Angelo
2
这让我的一天都变得美好了!!那句话 - 如果您为帐户设置了身份验证令牌,则在令牌失效之前,将不会调用getAuthToken方法 - 让我理解了一切。 - Apperside
文档中的那个句子毫无意义。因为它返回缓存的令牌,但如果令牌失效,它不会生成新的令牌,我们必须自己处理。这很愚蠢,因为我想检查过期日期,所以我不需要进行网络调用来判断令牌是否过期。但除非我可以在getAuthToken()内编写代码,否则编码不是很方便。 - Evren Yurtesen

-2

在AccountManager#getAuthToken方法中调用AuthenticatorActivity,你必须通过Parcelable将Intent发送到该Activity,示例代码如下:

    final Intent intent = new Intent(mContext, LoginActivity.class);
    intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, accountAuthenticatorResponse);
    intent.putExtra(LoginActivity.ARG_ACCOUNT_TYPE, account.type);
    intent.putExtra(LoginActivity.ARG_AUTH_TYPE, authTokenType);
    intent.putExtra(LoginActivity.ARG_ACCOUNT_NAME, account.name);
    final Bundle bundle = new Bundle();
    bundle.putParcelable(AccountManager.KEY_INTENT, intent);

这完全没有回答问题。 - Austyn Mahoney

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接