AndroidアプリからOAuth認証のウェブサービスにログインする
はじめに
- http://nirasan.hatenablog.com/entry/2012/10/28/170617 で作ったOAuth認証するウェブサービスにAndroidからログインする
参考サイト
https://developers.google.com/accounts/docs/MobileApps
https://sites.google.com/site/oauthgoog/oauth-practices/mobile-apps-for-complex-login-systems/samplecode
サンプルコードのとおりに実装
- サンプルコードは前述のこちら https://sites.google.com/site/oauthgoog/oauth-practices/mobile-apps-for-complex-login-systems/samplecode
- 実際のコードは下記の通り
src/com/example/oauthtest/MainActivity.java
package com.example.oauthtest; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.webkit.CookieSyncManager; public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); CookieSyncManager.createInstance(getApplicationContext()); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { // Start the WebViewActivity to handle the authentication. case R.id.login: Intent intent = new Intent(this, WebViewActivity.class); intent.setData(Uri.parse("http://mother.example.com:3000")); startActivityForResult(intent, 0); return true; // Exit. case R.id.exit: finish(); return true; } return super.onOptionsItemSelected(item); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case 0: if (resultCode != RESULT_OK || data == null) { return; } // Get the token. String token = data.getStringExtra("token"); if (token != null) { /* Use the token to access data */ Log.v("onActivityResult",token); } return; } super.onActivityResult(requestCode, resultCode, data); } }
com/example/oauthtest/WebViewActivity.java
package com.example.oauthtest; import android.app.Activity; import android.content.Intent; import android.graphics.Bitmap; import android.os.Bundle; import android.view.Menu; import android.view.Window; import android.webkit.CookieManager; import android.webkit.CookieSyncManager; import android.webkit.WebChromeClient; import android.webkit.WebView; import android.webkit.WebViewClient; public class WebViewActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Allow the title bar to show loading progress. requestWindowFeature(Window.FEATURE_PROGRESS); WebView webview = new WebView(this); setContentView(webview); // Enable JavaScript. webview.getSettings().setJavaScriptEnabled(true); webview.setWebChromeClient(new WebChromeClient() { // Show loading progress in activity's title bar. @Override public void onProgressChanged(WebView view, int progress) { setProgress(progress * 100); } }); webview.setWebViewClient(new WebViewClient() { // When start to load page, show url in activity's title bar @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { setTitle(url); } @Override public void onPageFinished(WebView view, String url) { CookieSyncManager.getInstance().sync(); // Get the cookie from cookie jar. String cookie = CookieManager.getInstance().getCookie(url); if (cookie == null) { return; } // Cookie is a string like NAME=VALUE [; NAME=VALUE] String[] pairs = cookie.split(";"); for (int i = 0; i < pairs.length; ++i) { String[] parts = pairs[i].split("=", 2); // If token is found, return it to the calling activity. if (parts.length == 2 && parts[0].equalsIgnoreCase("oauth_token")) { Intent result = new Intent(); result.putExtra("token", parts[1]); setResult(RESULT_OK, result); finish(); } } } }); // Load the page Intent intent = getIntent(); if (intent.getData() != null) { webview.loadUrl(intent.getDataString()); } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_web_view, menu); return true; } @Override protected void onPause() { super.onPause(); CookieSyncManager.getInstance().stopSync(); } @Override protected void onResume() { super.onResume(); CookieSyncManager.getInstance().startSync(); } }
サーバー側で認証成功時にクッキーでアクセス用のトークンを渡す
- 前述のサイトでは、サーバー側からアンドロイド側へのトークンの渡す際に、クッキーかタイトルを使うように記載されている。
- 今回はサンプルコードがクッキーを使っていたので、そのとおりにサーバー側を変更する。
コントローラの変更箇所
diff --git a/app/controllers/auth_controller.rb b/app/controllers/auth_controller.rb index 433f0a6..4168576 100644 --- a/app/controllers/auth_controller.rb +++ b/app/controllers/auth_controller.rb @@ -16,7 +16,9 @@ class AuthController < ApplicationController end token_pair.update_token!(@client.authorization) session[:token_id] = token_pair.id - redirect_to '/' + # redirect_to '/' + cookies[:oauth_token] = token_pair.access_token; + head :ok end
OAuth用の新しいクライアントIDを発行する
- 前回はローカルで動作確認をしていたため、OAuthのコールバック先をlocalhostとしていたので、新たにクライアントIDを発行する。
- 今回はAndroidのエミュレータから動作確認をするにあたり、検証用のドメイン「mother.example.com」を用意し、「http://mother.example.com:3000/oauth2callback」をコールバック先に登録する。
検証用のドメイン名をアンドロイド側のhostsに登録する
- http://gendosu.jp/archives/1564 に従いhostsに「10.0.2.2 mother.example.com」を追記する
動作確認
- エミュレータでアプリを実行し、メニューからloginを選択して、ログインを行い、ログにアクセストークンが表示されたら成功