Android OAuth2 Bearer令牌最佳做法

时间:2013-12-17 18:41:24

标签: android oauth-2.0 accountmanager android-syncadapter android-volley

This nice tutorial是Android上帐户身份验证的一个非常好的介绍,并通​​过使用Android的AccountManager来实现。

但是,我需要使用Bearer令牌为OAuth2 API创建客户端应用程序以进行身份​​验证。在获得令牌时,我收到了它的到期时间戳,但我不清楚存储的位置以及如何正确使用它。 问题是,如果我不想不必要地去服务器,应用程序会意识到,只有在请求任何随机资源时从服务器收到HTTP 401错误后,承载才会变为无效。那么,解决这个问题的最佳做法是什么:

  1. 在我的代码中的每个网络请求是否都有重试机制,以防承载令牌在此期间变为无效?在捕获异常时我可能invalidateAuthToken并重试。
  2. Sync Adapter可以在某种程度上帮助吗?
  3. 由于我是Android开发的新手,我希望解决方案也可能与我预期的完全不同。

    如果相关,我打算使用Volley进行服务器通信。

2 个答案:

答案 0 :(得分:9)

经过一番调查后,我发现了自己的答案:

  1. 是的,调用AccountManager#invalidateAuthToken会删除上次保存的身份验证令牌(OAuth2案例中的访问令牌),并希望您在下一次AccountAuthenticator#getAuthToken呼叫时检测到该令牌。例如,以下是该方法的代码:

    @Override
    public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
        // Extract the username and password from the Account Manager, and ask
        // for an appropriate AuthToken.
        final AccountManager am = AccountManager.get(mContext);
    
        String authToken = am.peekAuthToken(account, authTokenType);
    
        // EXTRA: I am also storing the OAuth2 refresh token in the AccountManager
        Map<String, String> refreshResult = null;
        String refreshToken = am.getUserData(account, KEY_REFRESH_TOKEN);
        if (TextUtils.isEmpty(authToken) && !TextUtils.isEmpty(refreshToken)) {
            // lets try to refresh the token
            // EXTRA: AuthenticationProvider is my class for accessing the authentication server, getting new access and refresh token based on the existing refresh token
            refreshResult = AuthenticationProvider.
                refreshAccessToken(am.getUserData(account, KEY_REFRESH_TOKEN));
        }
    
        // If we get a result from the refresh - we return it
        if (!refreshResult.isEmpty()) {
            authToken = refreshResult.get(AccountManager.KEY_AUTHTOKEN);
            // EXTRA: new refresh token used only in OAuth2
            refreshToken = refreshResult.get(KEY_REFRESH_TOKEN);
    
            final Bundle result = new Bundle();
            result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
            result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
    
            // store the new tokens in the system
            am.setAuthToken(account, authTokenType, authToken);
            am.setUserData(account, KEY_REFRESH_TOKEN, refreshToken);
    
            result.putString(AccountManager.KEY_AUTHTOKEN, refreshResult.get(AccountManager.KEY_AUTHTOKEN));
            result.putString(KEY_REFRESH_TOKEN, refreshResult.get(KEY_REFRESH_TOKEN));
            return result;
        }
    
        // If we get here, then we couldn't access the user's password - so we
        // need to re-prompt them for their credentials. We do that by creating
        // an intent to display our AuthenticatorActivity.
        final Intent intent = new Intent(mContext, LoginActivity.class);
        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
        final Bundle bundle = new Bundle();
        bundle.putParcelable(AccountManager.KEY_INTENT, intent);
        return bundle;
    }
    

    我还收到了问题中提到的confirmation from the author of the blog post

  2. SyncAdapter无法直接帮助,因为它们的真正目的是异步(对于开发人员)和透明地(对于用户)从网络获取数据。他们只需使用AbstractAccountAuthenticator并在适当的地方调用其方法。

答案 1 :(得分:1)

之前我遇到了同样的问题,并在Android中将此library转换为handel OAuth2。但该库是Retrofit的扩展,它简化了对OAuth 2提供程序进行身份验证的过程,但您仍然可以使用它。