【问题标题】:How to implement AccountManager in my app如何在我的应用中实现 AccountManager
【发布时间】:2015-03-11 17:03:13
【问题描述】:

我尝试在我的应用中实现帐户管理器,以避免用户每次打开应用时都必须登录。

所以基本上,我已经有了我的身份验证活动,用户可以在其中输入其登录名和密码,以及我们从服务器接收令牌的位置(目前身份验证是基本的)。现在我想添加 AccountManager 但我真的不明白哪个部分会去哪里。

我需要的是非常基本的:

  • 如果我以前从未登录过,请添加一个帐户
  • 如果我的帐户存在则自动登录
  • 如果自动身份验证不起作用,请在服务器上获取新令牌

这是我的代码:

AuthenticationActivity.java

public class AuthenticationActivity extends Activity {

    private EditText editTextUsername;
    private EditText editTextPassword;
    private Button buttonLogin;
    private ProgressBar spinner;
    private TextView error;
    private TextView register;

    private boolean accountRegistred;

    AccountManager accountManager;

    public static final String AUTHENTICATION = "authentication"; //action

    private ConnectionSuccessReceiver connectionSuccessReceiver = new ConnectionSuccessReceiver();

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

        accountManager = AccountManager.get(this);
        Account[] accounts = accountManager.getAccountsByType("login");

        if (accounts.length > 0) {
            //If there is an account
        } else {
            accountRegistred = false;
            editTextUsername = (EditText) findViewById(R.id.editText_login);
            editTextUsername.setVisibility(View.VISIBLE);
            editTextPassword = (EditText) findViewById(R.id.editText_password);
            editTextPassword.setVisibility(View.VISIBLE);
            buttonLogin = (Button) findViewById(R.id.button_connection);
            buttonLogin.setVisibility(View.VISIBLE);
            error = (TextView) findViewById(R.id.textView_error);
            register = (TextView) findViewById(R.id.textView_register);
            register.setVisibility(View.VISIBLE);
            spinner = (ProgressBar) findViewById(R.id.progressBar);

            buttonLogin.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    //Here we start the service which will reach the server 
                    Intent i = new Intent(getApplicationContext(), AuthenticationService.class);
                    i.putExtra("username", editTextUsername.getText().toString());
                    i.putExtra("password", editTextPassword.getText().toString());
                    getApplication().startService(i);
                    spinner.setVisibility(View.VISIBLE);
                    error.setVisibility(View.INVISIBLE);
                }
            });

            register.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    startActivity(new Intent(AuthenticationActivity.this, RegisterActivity.class));
                }
            });
        }
        registerReceiver(connectionSuccessReceiver, new IntentFilter(AUTHENTICATION));
    }

    private class ConnectionSuccessReceiver extends BroadcastReceiver {
        //Called when the server returns success after authentication, we get the TOKEN here
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getStringExtra("STATE").equals("CONNECTED")) {
                Intent i = new Intent(AuthenticationActivity.this, MainActivity.class);
                i.putExtra("TOKEN", intent.getStringExtra("TOKEN"));
                startActivity(i);
            } else {
                spinner.setVisibility(View.INVISIBLE);
                error.setVisibility(View.VISIBLE);
            }
            finish();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(connectionSuccessReceiver);
    }
}

AuthenticatorService.java

public class AuthenticatorService extends Service {

    /**
     * The implementation of the class |AccountAuthenticatorImpl|.
     * It is implemented as a singleton
     */
    private static AccountAuthenticator accountAuthenticator = null;

    /**
     * The main constructor.
     */
    public AuthenticatorService() {
        super();
    }

    /**
     * The bind method of the service.
     * @param intent The intent used to invoke the service
     * @return The binder of the class which has implemented |AbstractAccountAuthenticator|
     */
    @Override
    public IBinder onBind(Intent intent) {
        IBinder ret = null;
        if (intent.getAction().equals(android.accounts.AccountManager.ACTION_AUTHENTICATOR_INTENT)) {
            ret = getAuthenticator().getIBinder();
        }
        return ret;
    }

    /**
     * The method used to obtain the authenticator. It is implemented as a singleton
     * @return The implementation of the class |AbstractAccountAuthenticator|
     */
    private AccountAuthenticator getAuthenticator() {
        if (AuthenticatorService.accountAuthenticator == null) {
            AuthenticatorService.accountAuthenticator = new AccountAuthenticator(this);
        }

        return AuthenticatorService.accountAuthenticator;
    }

    public class AccountAuthenticator extends AbstractAccountAuthenticator {
        private Context context;

        public AccountAuthenticator(Context context) {
            super(context);
            this.context = context;
        }

        @Override
        public Bundle editProperties(AccountAuthenticatorResponse accountAuthenticatorResponse, String s) {
            return null;
        }

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

            Bundle reply = new Bundle();

            Intent i = new Intent(context, AuthenticationActivity.class);
            i.setAction("com.readyo.app.authentication.addnewaccount");
            i.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
            i.putExtra("AuthTokenType", authTokenType);

            reply.putParcelable(AccountManager.KEY_INTENT, i);

            return reply;
        }

        @Override
        public Bundle confirmCredentials(AccountAuthenticatorResponse accountAuthenticatorResponse, Account account, Bundle bundle) throws NetworkErrorException {
            return null;
        }

        @Override
        public Bundle getAuthToken(AccountAuthenticatorResponse accountAuthenticatorResponse, Account account, String s, Bundle bundle) throws NetworkErrorException {
            return null;
        }

        @Override
        public String getAuthTokenLabel(String s) {
            return null;
        }

        @Override
        public Bundle updateCredentials(AccountAuthenticatorResponse accountAuthenticatorResponse, Account account, String s, Bundle bundle) throws NetworkErrorException {
            return null;
        }

        @Override
        public Bundle hasFeatures(AccountAuthenticatorResponse accountAuthenticatorResponse, Account account, String[] strings) throws NetworkErrorException {
            return null;
        }
    }
}

我还有通过 HTTP 访问服务器的代码,但我不确定它在这里是否重要。

感谢您的宝贵时间。

【问题讨论】:

    标签: android authentication access-token accountmanager


    【解决方案1】:

    回复有点晚,但也许这个示例可以帮助您: https://github.com/dawidgdanski/AccountAuthenticatorExample

    我前段时间创建了它,但注册/登录的逻辑可能会有所帮助

    add an account if I never logged in before:
    
    1. 如果您的应用流程要求用户登录才能访问数据,那么只需将您的 LoginActivity 声明为要显示的主要活动。

    验证和验证用户凭据后,调用 AccountManager.addAccountExcplicitly() 方法。

    1. 另一方面,如果您公开一些屏幕供匿名用户查看,则在您提供登录/注册功能的应用程序部分(设置或其他)中调用 AccountManager.addAccount()。此调用会激活您的 AccountAuthenticator,它会在 YourAccountAuthenticator.addAccount() 中处理您的请求,并可能会根据您的需要显示 LoginActivity/SignUpActivity。

    请记住,您也可以从系统设置中创建应用专用帐户。

        log automatically if my account exists
    

    好吧,我不确定我是否正确理解了您的需求。一旦您将 Account 存储在 AccountManager 的元数据中,只要您调用 AccountManager.getAccountsByType("my.account.type") 就可以使用它。 如果您想自动登录,那么您必须在某个地方存储您的凭据,这显然会受到敏感数据泄露的威胁。

     if the auto authentication doesn't work get a new token on the server
    

    有一个 AccountManager.invalidateAuthToken() 方法可以删除当前存储的 authToken 并调用另一个。

    您可以启动示例应用程序,我认为它至少可以解决您的一些问题,因为它涵盖了以下逻辑:

    • 登录/注册
    • 身份验证令牌失效
    • 显示当前登录的帐户
    • 注销

    干杯

    【讨论】:

      猜你喜欢
      • 2012-07-26
      • 2014-07-30
      • 2012-07-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-14
      相关资源
      最近更新 更多