The following steps are needed to get authenticated with Google App Engine
- Get a list of google accounts stored on the device
- Have the user choose which account they would like to use
- Request an authentication token
- If the response to the token is an Intent then start a new activity to get users permission to use that account otherwise save the token for the next step
- Use the token to request an auth cookie
- All done! Now you can use the auth cookie to make authenticated requests
Android Manifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.as400samplecode"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="15"
android:targetSdkVersion="15" />
<uses-permission android:name="android.permission.GET_ACCOUNTS"></uses-permission>
<uses-permission android:name="android.permission.USE_CREDENTIALS"></uses-permission>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/title_activity_main"
android:launchMode="standard"
android:multiprocess="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Application Layout - activity_main.xml
<?xml version="1.0" encoding="UTF-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:layout_marginBottom="10dp" android:text="@string/choose_account" android:textAppearance="?android:attr/textAppearanceMedium" android:textStyle="bold" /> <Spinner android:id="@+id/account" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_below="@+id/textView1" /> <Button android:id="@+id/startAuth" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_below="@+id/account" android:layout_marginTop="10dp" android:text="@string/start_auth" /> <Button android:id="@+id/expireToken" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_below="@+id/startAuth" android:layout_marginTop="10dp" android:text="@string/expire_token" /> </RelativeLayout>
Application Activity - MainActivity.java
package com.as400samplecode;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpParams;
import android.os.AsyncTask;
import android.os.Bundle;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerCallback;
import android.accounts.AccountManagerFuture;
import android.app.Activity;
import android.content.Intent;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;
import android.widget.Toast;
public class MainActivity extends Activity implements OnClickListener{
private String LOG_TAG = "GAEAuthMainActivity";
private static final int USER_PERMISSION = 989;
private AccountManager accountManager;
private Account[] accounts;
boolean expireToken = false;
private DefaultHttpClient httpclient = new DefaultHttpClient();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Spinner spinner = (Spinner) findViewById(R.id.account);
//create an ArrayAdaptar from the String Array
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item, getAccountList());
//set the view for the Drop down list
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
//set the ArrayAdapter to the spinner
spinner.setAdapter(dataAdapter);
Button startAuth = (Button) findViewById(R.id.startAuth);
startAuth.setOnClickListener(this);
Button expireToken = (Button) findViewById(R.id.expireToken);
expireToken.setOnClickListener(this);
}
public void onClick(View v) {
Spinner spinner = (Spinner) findViewById(R.id.account);
Account account = accounts[spinner.getSelectedItemPosition()];
switch (v.getId()) {
//send request to get a new or existing token
case R.id.startAuth:
expireToken = false;
accountManager.getAuthToken(account, "ah", null, false, new OnTokenAcquired(), null);
break;
//send request to expire a token
case R.id.expireToken:
expireToken = true;
accountManager.getAuthToken(account, "ah", null, false, new OnTokenAcquired(), null);
break;
// More buttons go here (if any) ...
}
}
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
switch(requestCode) {
//if the user approved the use of the account make another request
//for the auth token else display a message
case USER_PERMISSION:
if (resultCode == RESULT_OK) {
Spinner spinner = (Spinner) findViewById(R.id.account);
Account account = accounts[spinner.getSelectedItemPosition()];
accountManager.getAuthToken(account, "ah", null, false, new OnTokenAcquired(), null);
}
else if(resultCode == RESULT_CANCELED){
Toast.makeText(getBaseContext(), "Permission denied by User!",
Toast.LENGTH_LONG).show();
}
break;
}
}
// get a list of all Google accounts stored in the device account manager
// and then display them in a spinner for selection
private ArrayList<String> getAccountList(){
ArrayList<String> accountList = new ArrayList<String>();
accountManager = AccountManager.get(getApplicationContext());
accounts = accountManager.getAccountsByType("com.google");
for(Account account: accounts){
Log.v(LOG_TAG, account.name + "/" + account.type);
accountList.add(account.name);
}
return accountList;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
//the result for the auth token request is returned to your application
//via the Account Manager Callback you specified when making the request.
//check the returned bundle if an Intent is stored against the AccountManager.KEY_INTENT key.
//if there is an Intent then start the activity using that intent to ask for user permission
//otherwise you can retrieve the auth token from the bundle.
private class OnTokenAcquired implements AccountManagerCallback<Bundle> {
public void run(AccountManagerFuture<Bundle> result) {
Bundle bundle;
try {
bundle = (Bundle) result.getResult();
if (bundle.containsKey(AccountManager.KEY_INTENT)) {
Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT);
intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_NEW_TASK);
startActivityForResult(intent, USER_PERMISSION);
} else {
setAuthToken(bundle);
}
}
catch(Exception e){
e.printStackTrace();
}
}
};
//using the auth token and ask for a auth cookie
protected void setAuthToken(Bundle bundle) {
String authToken = bundle.getString(AccountManager.KEY_AUTHTOKEN);
if(expireToken){
accountManager.invalidateAuthToken("ah", authToken);
}
else {
new GetCookie().execute(authToken);
}
}
//using the token to get an auth cookie
private class GetCookie extends AsyncTask<String, Void, Boolean> {
HttpParams params = httpclient.getParams();
private HttpResponse response;
protected Boolean doInBackground(String... tokens) {
try {
// Don't follow redirects
params.setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, false);
HttpGet httpGet = new HttpGet("http://{replace_your_subdomain}.appspot.com/_ah/login?continue=http://localhost/&auth=" + tokens[0]);
response = httpclient.execute(httpGet);
ByteArrayOutputStream out = new ByteArrayOutputStream();
response.getEntity().writeTo(out);
out.close();
if(response.getStatusLine().getStatusCode() != 302){
// Response should be a redirect
Log.v(LOG_TAG, "No cookie");
return false;
}
//check if we received the ACSID or the SACSID cookie, depends on http or https request
for(Cookie cookie : httpclient.getCookieStore().getCookies()) {
Log.v(LOG_TAG, cookie.getName());
if(cookie.getName().equals("ACSID") || cookie.getName().equals("SACSID")){
Log.v(LOG_TAG, "Got cookie");
return true;
}
}
} catch (ClientProtocolException e) {
e.printStackTrace();
cancel(true);
} catch (IOException e) {
e.printStackTrace();
cancel(true);
} catch (Exception e) {
e.printStackTrace();
cancel(true);
} finally {
params.setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, true);
}
return false;
}
protected void onPostExecute(Boolean result) {
Log.v(LOG_TAG, "Done cookie");
new MyAuthenticatedRequest().execute("http://{replace_your_subdomain}.appspot.com/hello");
}
}
//make your authenticated request here using the same httpclient that received the cookie
private class MyAuthenticatedRequest extends AsyncTask<String, Void, Boolean> {
private HttpResponse response;
private String content = null;
protected Boolean doInBackground(String... urls) {
try {
HttpGet httpGet = new HttpGet(urls[0]);
response = httpclient.execute(httpGet);
StatusLine statusLine = response.getStatusLine();
Log.v(LOG_TAG, statusLine.getReasonPhrase());
for(Cookie cookie : httpclient.getCookieStore().getCookies()) {
Log.v(LOG_TAG, cookie.getName());
}
if(statusLine.getStatusCode() == HttpStatus.SC_OK){
ByteArrayOutputStream out = new ByteArrayOutputStream();
response.getEntity().writeTo(out);
out.close();
content = out.toString();
return true;
}
} catch (ClientProtocolException e) {
e.printStackTrace();
cancel(true);
} catch (IOException e) {
e.printStackTrace();
cancel(true);
} catch (Exception e) {
e.printStackTrace();
cancel(true);
}
return false;
}
//display the response from the request above
protected void onPostExecute(Boolean result) {
Log.v(LOG_TAG, content);
Toast.makeText(getBaseContext(), "Response from request: " + content,
Toast.LENGTH_LONG).show();
}
}
}
No comments:
Post a Comment
NO JUNK, Please try to keep this clean and related to the topic at hand.
Comments are for users to ask questions, collaborate or improve on existing.