2013年06月24日

【Chrome】Packaged Apps で OAuth2認証する超簡単なサンプル【Google】

Packaged Apps で OAuth2認証を使う超簡単なサンプルを紹介しよう。

$git clone https://github.com/GoogleChrome/chrome-app-samples.git

今回は上のコマンドでダウンロードしたサンプルアプリ群の中から、「identity」というプロジェクトを参考にした。

Packaged Apps ではOAuth2認証に Chrome Identity API というのを使う。
Googleアカウント以外の認証にも使えるが、今回はなるべく理解を容易にするためにGoogleアカウント認証のサンプルのみ。
これはログインしたGoogleアカウントに紐づくユーザ名を画面に表示するだけの超簡単なサンプルアプリである。

要する作業は以下の通りとなる。

(1)manifest.jsonにpermissionsを与える。

(2)既にインストールされているアプリのmanifest.jsonから "key"項目をコピーして、ソースのmanifest.jsonへペースト。
これがどういうことかというと、ソース上のmanifest.jsonのテキトーな"key"もインストール後は適切な値に変わってるので、正式にリリースするときはこれを使ってねってこと(だと思う)。

ちなみにアプリがインストールされている場所は、
Windows7の場合:
C:/Users/<USER>/AppData/Local/Google/Chrome/User Data/Default/Extensions
MacOSの場合:
~/Library/Application Support/Google/Chrome/Default/Extensions

(3)Client IDを取得する。
Google APIs Consoleに行って Client ID を新規発行する。

(4)取得したClient IDをmanifest.jsonへコピペ。

(5)以上でAuth Token が取得可能。ログインが必要なGoogle APIへアクセスできる。

以上。

ではmanifest.jsonから見てみよう。
{
  "name": "Identity API",
  "version": "1",
  "manifest_version": 2,
  "minimum_chrome_version": "23",
  "key": "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefgh",
  "app": {
    "background": {
      "scripts": ["main.js"]
    }
  },
  "permissions": ["experimental"],
  "oauth2": {
    "client_id": "503955758982.apps.googleusercontent.com",
    "scopes": ["https://www.googleapis.com/auth/userinfo.profile"]
  }
}
見てのとおり、 key には"abcdefg...."とテキトーな文字列が入力されている。
permissionsは権限を設定、oauth2.client_idにはGoogle APIs Consoleで取得したClient IDを、oauth2.scopesには利用するGoogle APIをURLを登録する。

次は画面HTMLだ。
index.html
<html>
  <head>
    <title>Identity API Sample App</title>
    <script src="identity.js"></script>
  </head>
  <body>
    <div id="user_info"></div>
    <button id="signin" style="display:none">Sign in</button>
  </body>
</html>
「Sign in」ボタンだけの簡単な画面だ。
実際の処理がコーディングされている identity.js をscriptタグで読み込んでいる。
まー特に説明するまでもないだろう。

次はmain.js
chrome.app.runtime.onLaunched.addListener(function() {
  chrome.app.window.create('index.html', { "bounds": { "width": 1024, "height": 768 } });
});
Packaged Appsの画面描画の際の振る舞いが記述されている。
このファイルはmanifest.jsonのapp.background.scriptsで定義されている。

最後は最も重要な identity.js だ。
function onImageFetched(e) {
  var elem = document.getElementById('user_info');
  if (!elem) return;
  if (this.status != 200) return;
  var imgElem = document.createElement('img');
  imgElem.src = window.webkitURL.createObjectURL(this.response);
  elem.appendChild(imgElem);
}

function fetchImageBytes(user_info) {
  if (!user_info || !user_info.picture) return;
  var xhr = new XMLHttpRequest();
  xhr.open('GET', user_info.picture, true);
  xhr.responseType = 'blob';
  xhr.onload = onImageFetched;
  xhr.send();
}

function populateUserInfo(user_info) {
  var elem = document.getElementById('user_info');
  if (!elem) return;
  var nameElem = document.createElement('div');
  nameElem.innerHTML = "<b>Hello " + user_info.name + "</b>";
  elem.appendChild(nameElem);
  fetchImageBytes(user_info);
}

function onUserInfoFetched(e) {
  if (this.status != 200) return;
  console.log("Got the following user info: " + this.response);
  var user_info = JSON.parse(this.response);
  populateUserInfo(user_info);
}

function onGetAuthToken(auth_token) {
  var userInfoDiv = document.getElementById('user_info');
  if (!auth_token) {
    var signinButton = document.createElement('button');
    signinButton.id = 'signin';
    signinButton.appendChild(document.createTextNode('Sign In'));
    signinButton.onclick = getUserInfoInteractive;
    userInfoDiv.appendChild(signinButton);
    return;
  }
  // Remove the sign in button if it exists.
  if (userInfoDiv.firstChild) {
    userInfoDiv.removeChild(userInfoDiv.firstChild);
  }
  // Use the auth token to do an XHR to get the user information.
  var xhr = new XMLHttpRequest();
  xhr.open('GET', 'https://www.googleapis.com/oauth2/v1/userinfo?alt=json');
  xhr.setRequestHeader('Authorization', 'Bearer ' + auth_token);
  xhr.onload = onUserInfoFetched;
  xhr.send();
}

function getUserInfo() {
  chrome.experimental.identity.getAuthToken({ 'interactive': false }, onGetAuthToken);
}

function getUserInfoInteractive() {
  chrome.experimental.identity.getAuthToken({ 'interactive': true }, onGetAuthToken);
}

window.onload = getUserInfo;
処理の流れをおおまかに書くと、

1.window.onload時にgetUserInfo()が呼ばれる。
2.chrome.experimental.identity.getAuthToken()がinteractive=false(つまり対話無しログインモード)で呼ばれる。
3.AuthToken取得時の非同期処理onGetAuthToken()が呼ばれる。
4.AuthTokenが取得できなければログイン画面へ。AuthTokenが取得出来たら(つまりログイン状態なら)ユーザ情報取得APIをXMLHttpRequest(xhr)で叩く。
5.xhr.onloadに登録されたonUserInfoFetched()でユーザ情報取得APIからのレスポンスJSONを受け取る。
6.受け取ったユーザ情報JSONをパースして画面へ表示。
7.ユーザ情報にプロフィール画像があればそれも描画。

となる。

念のために書いておくが、このサンプルアプリはChromeへインストールしないと動作しない。アプリのインストール方法は以前のエントリをご参照あれ。

参考
Identify User - Google Chrome chrome-app-samples/Identity at master・GoogleChrome/chrome-app-samples・GitHub

関連エントリ
【Chrome】Packaged Apps アプリをHelloWorld【Google】
スマホOSの主導権争いの行方
posted by 寄り道退屈男 at 13:12 | Comment(0) | TrackBack(0) | Packaged Apps
この記事へのコメント
コメントを書く
お名前: [必須入力]

メールアドレス: [必須入力]

ホームページアドレス:

コメント: [必須入力]

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
この記事へのトラックバックURL
http://blog.sakura.ne.jp/tb/69937540
※言及リンクのないトラックバックは受信されません。

この記事へのトラックバック