nirasan's tech blog

趣味や仕事の覚え書きです。Linux, Perl, PHP, Ruby, Javascript, Android, Cocos2d-x, Unity などに興味があります。

AndroidアプリからOAuth認証のウェブサービスにログインする

はじめに

サンプルコードのとおりに実装

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();
    }
}
AndroidManifest.xml
  • uses-permission に android.permission.INTERNET を追加

サーバー側で認証成功時にクッキーでアクセス用のトークンを渡す

  • 前述のサイトでは、サーバー側からアンドロイド側へのトークンの渡す際に、クッキーかタイトルを使うように記載されている。
  • 今回はサンプルコードがクッキーを使っていたので、そのとおりにサーバー側を変更する。
コントローラの変更箇所
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を発行する

検証用のドメイン名をアンドロイド側のhostsに登録する

動作確認

  • エミュレータでアプリを実行し、メニューからloginを選択して、ログインを行い、ログにアクセストークンが表示されたら成功