AWS Cognito结合多个帐户的Android帐户管理器

时间:2017-06-10 18:07:15

标签: android amazon-web-services amazon-cognito accountmanager

我想向我的应用的用户展示一系列要使用的帐户(启用共享设备,例如一个部门,但仍然能够识别用户)。 用户标识和授权通过AWS Cognito用户池工作 - >联合身份 - > STS。

我的问题是,我似乎无法让AWS SDK与Android帐户管理器(我也想与SyncManager一起使用)很好地集成。

所以这是我目前的做法:

我试图将用户身份验证与api调用分开。用户身份验证应该通过AccountManager进行,一旦提供了AuthToken,就会配置CloudService(绑定到MainActivity)中的credentialsProvider,并且可以进行api调用。为了更多地使用AWS Cognito SDK,我创建了一个单例来保存UserPool,当前用户和会话,但没有真正的效果。

到目前为止,这个解决方案给我的是,我可以登录并使用该应用程序一段时间。 1小时后,我存储在AccountManager中的访问令牌已过期,我无法直接刷新它。我能够刷新令牌的唯一方法是不使用AccountManager,因为AWS CachedCredentialsProvider负责令牌刷新。但是,这是基于使用sharedPreferences而我无法看到当前缓存的用户是谁,因此不适合使用它。

长话短说,我试图将所有重要代码放在下面。我希望你能指出我正确的方向。可能我已经远离建筑...... 提前谢谢!

AccountSelectionActivity

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_account_selection);

    List<Account> availableAccounts = new ArrayList<>();
    mAdapter = new AccountsViewAdapter(availableAccounts, this);
    RecyclerView recyclerView = (RecyclerView) findViewById(R.id.rvAccountsList);
    if (null != recyclerView) {
        recyclerView.setLayoutManager(
            new LinearLayoutManager(getApplicationContext()));
        recyclerView.setAdapter(mAdapter);
    } else {
        Log.e(TAG, "no RecyclerView found");
    }

    accountManager = AccountManager.get(getApplicationContext());
    loadAvailableAccounts();
}

void loadAvailableAccounts(){
    Account[] accounts = accountManager.getAccountsByType(
        getString(R.string.account_type));
    if (0 == accounts.length) {
        addAccount(null);
    } else {
        mAdapter.setAccountsList(accounts);
    }
}

// called upon account selection
public void onClick(Account account) {
    selectedAccount = account;
    Intent intent = new Intent(this, MainActivity.class);
    Bundle bundle = new Bundle();
    bundle.putParcelable(AccountManager.KEY_ACCOUNT_NAME, selectedAccount);
    intent.putExtras(bundle);
    startActivity(intent);
    finish();
}

MainActivity

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    Bundle bundle = getIntent().getExtras();
    if (bundle != null) {
        mAccount = bundle.getParcelable(AccountManager.KEY_ACCOUNT_NAME);
        if (mAccount == null) {
            finishDueToMissingAccount();
        }
    } else {
        finishDueToMissingAccount();
    }

    setContentView(R.layout.activity_buddy);
    [...]
}

// called from base class after binding the CloudService
void onCloudServiceConnected() {
    if (mAccount != null ) {
        cloudService.logIn(mAccount, this);
    } else {
        Log.e(TAG, "mAccount = " + mAccount.toString());
    }
}

CloudService

@Override
public void onCreate() {
    accountManager = AccountManager.get(getApplicationContext());
    credentialsProvider = new CognitoCachingCredentialsProvider(
        this, // context
        IDENTITY_POOL_ID,
        IDENTITY_POOL_REGION);
    syncManager = new CognitoSyncManager(
        this, // context
        IDENTITY_POOL_REGION,
        credentialsProvider);
}

[...]

public void logIn(Account account, Activity activity) {
    this.account = account;
    accountManager.getAuthToken(account,
        "n/a", // token type
        null, // options
        activity,
        new OnTokenAcquired(), // callback
        null // handler
    );
}

private class OnTokenAcquired implements AccountManagerCallback<Bundle> {
    @Override
    public void run(AccountManagerFuture<Bundle> result) {
        try {
            Map<String, String> logins = new HashMap<>();
            String token = result.getResult().getString(
                AccountManager.KEY_AUTHTOKEN);
            logins.put(USER_POOL_ARN, token);
            credentialsProvider.setLogins(logins);
        } catch (IOException e) {
            // TODO: Handle Exception
        } catch (OperationCanceledException e) {
            // TODO: Handle Operation Canceled
        } catch (AuthenticatorException e) {
            // TODO: Hanlde Authenticator exception
        }
    }
}

身份验证

@Override
public Bundle addAccount(AccountAuthenticatorResponse response,
             String accountType, String authTokenType,
             String[] requiredFeatures,
             Bundle options) throws NetworkErrorException {
    return promptToLogin(response, options);
}

private Bundle promptToLogin(AccountAuthenticatorResponse response, Bundle options) {
    options = (options == null) ? new Bundle() : options;
    final Intent intent = new Intent(context, AuthenticatorActivity.class);
    intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
    intent.putExtras(options);

    final Bundle result = new Bundle();
    result.putParcelable(AccountManager.KEY_INTENT, intent);
    return result;
}

public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account,
    String authTokenType, Bundle options) throws NetworkErrorException {
    Bundle result = new Bundle();
    if (accountExists(account.type)) {
        String token = accountManager.peekAuthToken(account, authTokenType);
        if ( token != null ) {
            return passBackCurrentAuthToken(account.name, authTokenType,
                result, token);
        }
    }

    return promptToLogin(response, options);
}

private Bundle passBackCurrentAuthToken(String accountName, String authTokenType, Bundle bundle, String token) {
    bundle.putString(AccountManager.KEY_ACCOUNT_NAME, accountName);
    bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, authTokenType);
    bundle.putString(AccountManager.KEY_AUTHTOKEN, token);
    return bundle;
}

AuthenticatorActivity

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_authenticator);

    curSession = SessionSingleton.getInstance(getApplicationContext());
    etMail = (EditText) findViewById(R.id.etMail);
    etPass = (EditText) findViewById(R.id.etPass);

}

public void attemptLogin(View v) {
    showWaitDialog("Signing in...");
    curSession.getSessionInBackground(etMail.getText().toString(), authHandler);
}

AuthenticationHandler authHandler = new AuthenticationHandler() {
        @Override
        public void onSuccess(CognitoUserSession cognitoUserSession,
                              CognitoDevice cognitoDevice) {
            Bundle result = new Bundle();

            closeWaitDialog();
            try {
                Log.d(TAG, "> authHandler > onSuccess");
                curSession.setSession(cognitoUserSession);

                String token = curSession.getIdToken();
                result.putString(AccountManager.KEY_AUTHTOKEN, token);

                AccountManager accountManager = AccountManager.get(getApplicationContext());
                Account account = new Account(etMail.getText().toString(),
                                  getString(R.string.account_type));
                accountManager.addAccountExplicitly(account, token, result);
                accountManager.setAuthToken(account, "n/a", token);

                setAccountAuthenticatorResult(result);
                finish();
            } catch (Exception e) {
                showDialogMessage("ERROR", e.getLocalizedMessage());
            }
        }

        @Override
        public void getAuthenticationDetails(AuthenticationContinuation authenticationContinuation, String username) {
            String password = etPass.getText().toString();
            AuthenticationDetails authenticationDetails = new AuthenticationDetails(username, password, null);
            authenticationContinuation.setAuthenticationDetails(authenticationDetails);
            authenticationContinuation.continueTask();
        }

        @Override
        public void getMFACode(MultiFactorAuthenticationContinuation multiFactorAuthenticationContinuation) {
            closeWaitDialog();
            showDialogMessage("MFA is not supported", "");
        }

        @Override
        public void authenticationChallenge(final ChallengeContinuation continuation) {
            continuation.continueTask();
        }

        @Override
        public void onFailure(Exception e) {
            closeWaitDialog();
            showDialogMessage("Sign-in failed", formatException(e));
        }
    };

SessionSingleton

private SessionSingleton(Context context) {
    userPool = new CognitoUserPool(
        context,
        USER_POOL_ID,
        CLIENT_ID,
        CLIENT_SECRET,
        new ClientConfiguration(),
        USER_POOL_REGION);
}

void getSessionInBackground(String username, AuthenticationHandler authHandler) {
    user = userPool.getUser(username);
    user.getSessionInBackground(authHandler);
}

void setSession(CognitoUserSession session) {
    this.session = session;
}

CognitoUserSession getSession() {
    return session;
}

String getIdToken() {
    return session.getIdToken().getJWTToken();
}

0 个答案:

没有答案