Task
Create a one-time login feature using Android's authentication manager.
Current Process
I am currently using the Volley to read email and password from a form and send a request to a server
Required Change
To be able to create a one-time login for the use with credentials, using Android authentication manager following this post.
Question
1. My question lies in the implementation of the fetchTokenFromCredentials
method under the getAuthToken
of the authenticator class.
Here is the Java code snippet:
@Override
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options)
throws NetworkErrorException {
// We can add rejection of a request for a token type we
// don't support here
// Get the instance of the AccountManager that's making the
// request
final AccountManager am = AccountManager.get(mContext);
// See if there is already an authentication token stored
String authToken = am.peekAuthToken(account, authTokenType);
// If we have no token, use the account credentials to fetch
// a new one, effectively another logon
if (TextUtils.isEmpty(authToken)) {
final String password = am.getPassword(account);
if (password != null) {
authToken = fetchTokenFromCredentials(account.name, password, authTokenType)
}
}
// If we either got a cached token, or fetched a new one, hand
// it back to the client that called us.
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;
}
// If we get here, then we don't have a token, and we don't have
// a password that will let us get a new one (or we weren't able
// to use the password we do have). We need to fetch
// information from the user, we do that by creating an Intent
// to an Activity child class.
final Intent intent = new Intent(mContext, LoginActivity.class);
// We want to give the Activity the information we want it to
// return to the AccountManager. We'll cover that with the
// KEY_ACCOUNT_AUTHENTICATOR_RESPONSE parameter.
intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
// We'll also give it the parameters we've already looked up, or
// were given.
intent.putExtra(LoginActivity.ARG_IS_ADDING_NEW_ACCOUNT, false);
intent.putExtra(LoginActivity.ARG_ACCOUNT_NAME, account.name);
intent.putExtra(LoginActivity.ARG_ACCOUNT_TYPE, account.type);
intent.putExtra(LoginActivity.ARG_AUTH_TYPE, authTokenType);
// Remember that we have to return a Bundle, not an Intent, but
// we can tell the caller to run our intent to get its
// information with the KEY_INTENT parameter in the returned
// Bundle
final Bundle bundle = new Bundle();
bundle.putParcelable(AccountManager.KEY_INTENT, intent);
return bundle;
}
Previously I was using Volley , so my implementation of fetchTokenfromCredentials
was something like shown below. However, I cannot use the same implementation now because I need to 'return' an authentication string. Volley does the login asynchronously so even if i add a return type to the function below it will always return null. Question: How do i wrap around THIS situation. What alternatives can I use?
public void fetchTokenfromCredentials(String name, String password) {
JSONObject loginObject = new JSONObject();
try {
loginObject.put("email", email);
loginObject.put("password", password);
} catch(JSONException e) {
e.printStackTrace();
}
// assume predefined url and params
JsonObjectRequest loginRequest = new HeaderRequest(Request.Method.POST, url + params, loginObject, new Response.Listener < JSONObject > () {@Override
public void onResponse(JSONObject response) {
try {
JSONObject headers = response.getJSONObject("headers");
// A simple use class that stores the id, username etc.
user = new User(response.getInt("id"), response.getString("name"), response.getString("authentication_token"), response.getString("email"));
// Previous code started a new main activity intent here
} catch(JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {@Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, "Failed response");
}
});
RequestQueueSingleton.getInstance(this.getApplicationContext()).addToRequestQueue(loginRequest);
}