我有一个应用程序,它使用AccountManager存储用户的帐户。用户使用OAuth2.0密码-用户名凭据流登录并通过我的REST注册。
用户接收的访问令牌在2小时内到期,需要刷新直到再次过期,以此类推。
我需要在我的身份验证器中实现这个刷新功能。
我有一个名为AccessToken的模型,它有以下字段:
String accessToken, String tokenType, Long expiresIn, String refreshToken, String scope, Long createdAt。
因此,目前,在我的getAuthToken方法中,在AccountAuthenticator类中,我接收了这个AccessToken对象,并将它的accessToken字段用作帐户管理器的Auth Token。
我需要的是使用我的帐户管理器以某种方式存储刷新令牌和auth令牌,当应用程序试图访问API并获得错误响应:{"error": "access token expired"}时,使用来自先前接收到的refreshToken对象的refreshToken字符串刷新当前访问令牌。不过,我不知道该怎么做。
我在身份验证器类中的getAuthToken方法当前如下所示:
@Override
public Bundle getAuthToken(AccountAuthenticatorResponse accountAuthenticatorResponse, Account account,
String authTokenType, Bundle options) throws NetworkErrorException {
if (!authTokenType.equals(AccountGeneral.AUTHTOKEN_TYPE_READ_ONLY) &&
!authTokenType.equals(AccountGeneral.AUTHTOKEN_TYPE_FULL_ACCESS)) {
final Bundle result = new Bundle();
result.putString(AccountManager.KEY_ERROR_MESSAGE, "Invalid authTokenType");
return result;
}
final AccountManager manager = AccountManager.get(context.getApplicationContext());
String authToken = manager.peekAuthToken(account, authTokenType);
Log.d("Discounty", TAG + " > peekAuthToken returned - " + authToken);
if (TextUtils.isEmpty(authToken)) {
final String password = manager.getPassword(account);
if (password != null) {
try {
authToken = discountyService.getAccessToken(DiscountyService.ACCESS_GRANT_TYPE,
account.name, password).toBlocking().first().getAccessToken();
// =======
// Here the above discountyService.getAccessToken(...) call returns
// AccessToken object on which I call the .getAccessToken()
// getter which returns a string.
// =======
} catch (Exception e) {
e.printStackTrace();
}
}
}
if (!TextUtils.isEmpty(authToken)) {
final Bundle result = new Bundle();
result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
return result;
}
final Intent intent = new Intent(context, 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);
final Bundle bundle = new Bundle();
bundle.putParcelable(AccountManager.KEY_INTENT, intent);
return bundle;
}类AccountGeneral只包含一些常量:
public class AccountGeneral {
public static final String ACCOUNT_TYPE = "com.discounty";
public static final String ACCOUNT_NAME = "Discounty";
public static final String AUTHTOKEN_TYPE_READ_ONLY = "Read only";
public static final String AUTHTOKE_TYPE_READ_ONLY_LABEL = "Read only access to a Discounty account";
public static final String AUTHTOKEN_TYPE_FULL_ACCESS = "Full access";
public static final String AUTHTOKEN_TYPE_FULL_ACCESS_LABEL = "Full access to a Discounty account";
}该应用程序还将使用SyncAdapter,并将非常频繁地与API交互以同步来自服务器和服务器的数据,这些API调用还需要使用访问令牌作为请求中的参数,因此我确实需要实现这一刷新功能并使其自动化。
有人知道如何正确地实现这一点吗?
PS:我将使用一个本地数据库来存储我的所有数据,我也可以存储令牌对象。虽然不安全,但这似乎是一次简单的黑客攻击。也许我应该每次只存储一个刷新令牌作为db记录,并在应用程序接收到新令牌时更新它?
PPS:我可以自由地改变API的工作方式,所以如果有关于通过使API更好来改进移动应用程序的建议,他们也是非常感谢的。
发布于 2015-12-30 11:57:53
第一次添加帐户时,可以使用以下方法将刷新令牌保存到帐户的用户数据中:
Bundle userdata = new Bundle;
userdata.putString("refreshToken", refreshToken);
mAccountManager.addAccountExplicitly (account, password, userdata);您还可以在添加帐户后通过调用:
mAccountManager.setUserData(account, "refreshToken", refreshToken);当访问令牌过期时,可以通过以下方式检索刷新令牌:
String refreshToken = mAccountManager.getUserData(account, "refreshToken");使用refreshToken检索新的访问令牌。
https://stackoverflow.com/questions/34528472
复制相似问题