如果身份验证器

时间:2015-12-30 11:18:07

标签: android api authentication access-token accountmanager

我有一个使用AccountManager存储用户的应用程序'账户。用户使用OAuth2.0 password-username凭据流登录并通过我的REST API注册。

用户收到的访问令牌将在2小时后过期,需要刷新才能再次过期,依此类推。

我需要在验证器中实现此刷新功能。

我有一个名为AccessToken的模型,其中包含以下字段:

String accessToken, String tokenType, Long expiresIn, String refreshToken, String scope, Long createdAt

目前,我在getAuthToken课程的AccountAuthenticator方法中收到了此AccessToken个对象,并将accessToken字段用作Auth Token我的客户经理

我需要的是以某种方式使用我的客户经理存储刷新令牌和身份验证令牌,当应用尝试访问API并获得错误响应时:{"error": "access token expired"},使用{刷新当前访问令牌来自先前收到的refreshToken对象的{1}}字符串。但是,我不确定应该怎么做。

验证程序类中的AccessToken方法目前如下所示:

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"; } 并且会经常与API进行交互以将数据同步到服务器,并且这些API调用还需要使用访问令牌作为请求中的参数,因此我真的需要实现这个刷新功能并使其自动化。

有人知道如何正确实现吗?

PS:我将使用本地数据库存储我的所有数据,我也可以存储令牌对象。这似乎是一个容易入侵,虽然不安全。也许我应该一次只存储一个刷新令牌作为db记录,并在应用程序收到新令牌时更新它?

PPS:我可以随意更改API的工作方式,因此如果有更好的API改进移动应用的建议,我们也非常感激。

1 个答案:

答案 0 :(得分:6)

您可以在首次使用以下帐户添加帐户时将刷新令牌保存到帐户的用户数据中:

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检索新的访问令牌。