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.