Google+ログインボタンをサイトに設置する

前回の「Google+ログインボタンを使ったユーザー登録とログイン機能の作り方」でGoogle プロジェクトとGoogle+ APIやGoogle OAuth APIを使うためのGoogle App Engineアプリの作り方について説明しました。今回はGoogle+ ボタンの設置について説明していきます。

また、今回のサンプルはSlim3とjqueryを使っていますが、これらについての説明は割愛させて頂きます。

Google+ ログインボタンの設置

まず、indexページを作成してGoogle+ ログインボタンを設置してみましょう。

indexページのコントローラークラス(Slim3)

indexページのコントローラークラスを以下のように作成します。このindexコントローラーはindex.jspをフォーワードします。「state」はなりすましを防止するための乱数です。この乱数をindexページが表示されるタイミングでセッションに保存し、さらにindexページで表示するGoogle+ ログインボタンのリクエストパラメーターとしても設定します。(後ほどまた説明します)

public class IndexController extends Controller {

    @Override
    public Navigation run() throws Exception {

        // リクエストのなりすまし防止用の状態トークンを作成します。
        // 後の検証に備えてセッションで保存します。
        String state = new BigInteger(130, new SecureRandom()).toString(32);
        sessionScope("state", state);
        requestScope("state", state);

        return forward("index.jsp");
    }
}

index.jspにGoogle+ ボタンと必要なJavaScriptを追加

index.jspでは、まずGoogle+ログインボタンを表示するためのJavaScriptライブラリを以下のように読込みます。

		<!-- Google+ ログインボタンを表示するためのJavaScript Start -->
  		<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
  		<script type="text/javascript">
    		(function () {
      			var po = document.createElement('script');
      			po.type = 'text/javascript';
      			po.async = true;
      			po.src = 'https://plus.google.com/js/client:plusone.js?onload=start';
      			var s = document.getElementsByTagName('script')[0];
      			s.parentNode.insertBefore(po, s);
    		})();
  		</script>
  		<!-- Google+ ログインボタンを表示するためのJavaScript End -->

次に、Google+ ログインボタンを以下のように好きな場所に設置してください。Google+ ログインボタンをカスタムしたい方はこちらを参考ください。

		<!-- Google+ ログインボタン Start -->
		<div id="signinButton">
			<span class="g-signin"
				data-scope="https://www.googleapis.com/auth/plus.login 
				https://www.googleapis.com/auth/userinfo.email"
				data-clientid="<your client id>"
				data-redirecturi="postmessage"
				data-accesstype="offline"
				data-cookiepolicy="single_host_origin"
				data-callback="signInCallback"></span>
		</div>
		<!-- Google+ ログインボタン End -->

「data-scope」にはアプリがアクセスする必要のあるユーザー情報のスコープ(範囲)を設定します。今回のようにGoogle+アカウントを使ってユーザー登録をする場合は、ユーザーにGoogle+にログインしてもらい、ログインしたアカウントのメールアドレスを取得する必要があるため、ログインさせるための「https://www.googleapis.com/auth/plus.login」とメールアドレスを取得するための「https://www.googleapis.com/auth/userinfo.email」が必要になります。このように、アプリがアクセスするユーザーの情報に合わせて、必要なスコープをここで指定します。また、複数のスコープを指定する場合は半角スペースで区切ります。

「data-clientid」は前回作成したGoogle プロジェクトのクライアントIDです。詳しくは「Google+ログインを使うためのGoogle App Engineアプリの作成方法」をご参照ください。

「data-callback」はユーザーがGoogle+ ログインボタンをクリックした場合などに実行されるJavaScriptのコールバック関数名です。それ以外の設定項目について知りたい方はGoogleのドキュメントをご参照ください。

最後にコールバック関数について説明します。このJavaScriptのコールバック関数を</body>の直前に追加します。

		<!-- ユーザーログイン後のコールバック Start -->
		<script type="text/javascript">
			function signInCallback(authResult) {
			// デバッグ用ログの表示
			console.log(authResult);

  			if (authResult['code']) {

				 // ユーザーが認証されたのでログイン ボタンを非表示にします。例:
     			$('#signinButton').attr('style', 'display: none');

    			// コードをサーバーに送信します
     			$.ajax({
      				type: 'POST',
      				url: '/addUser?state=${state}',
      				data: {'code': authResult['code']},
      				success: function(result) {
      					window.location = "/user/userTop";
      				},
      				error : function(){
      					$('#result').html('ログイン失敗しました。');
      				}
    			});
  			} else if (authResult['error']) {
    			// エラーが発生しました。
    			// 可能性のあるエラー コード:
    			//   「access_denied」 - ユーザーがアプリへのアクセスを拒否しました
    			//   「immediate_failed」 - ユーザーを自動的にログインできませんでした
    			// console.log(「There was an error: 」 + authResult[「エラー」]);
  			}
		}
		</script>
		<!-- ユーザーログイン後のコールバック End -->

このコールバック関数の引数「authResult」にはJson形式の様々な情報が詰まっています。例えば、承認情報を受け取るためのワンタイムコードやユーザーのログイン情報などが入っています。デバッグ用ログも出力しているので、必要な場合はご確認ください。

ワンタイムコード承認フローの肝となるワンタイムコードは「authResult['code']」で受け取れます。ここではワンタイムコードを正常に取得できた場合、ajaxを使ってユーザー登録用のコントローラーにこの「ワンタイムコード」と「state」を転送しています。

リクエストパラメーターを使って「state」を転送することで、ユーザー登録用のコントローラー側で先ほどセッションに格納した「state」と比較して、なりすましかどうかの判定を行えます。

また、ユーザー登録用のコントローラーの処理が正常に終了するとwindow.location を使ってログイン後のユーザーページ「/user/userTop」に遷移しています。 ユーザー登録に失敗した場合はエラーメッセージ「ログイン失敗しました。」をHTMLに書き込みます。このエラーを表示する場合は以下のHTMLタグを出力したい場所に追加してください。

<div id="result"></div>

なりすまし防止のためのStateチェック

先ほどコールバック関数のPOST先である/addUser のコントローラーを作成し、以下のようにリクエストパラメーターに含まれてるStateとセッション上のStateをチェックします。

public class AddUserController extends Controller {

・・・<略>・・・・

    /**
     * チェックステート(なりすまし防止)
     * <pre>
     * リクエストのなりすましが行われておらず、この接続要求を送ったユーザーが、
     * 想定されたユーザーであることをここで確認します。
     * </pre>
     */
    private void checkState() throws Exception {
        // 承認リクエストに含まれるステート
        String requestState = asString("state");
        // セッションに含まれるステート
        String sessionState = sessionScope("state");

        // リクエストのなりすましが行われておらず、この接続要求を送ったユーザーが、
        // 想定されたユーザーであることをここで確認します。
        if (!requestState.equals(sessionState)) {
            throw new Exception();
        }
    }

・・・<略>・・・・


Google+ ログインボタンを使ってログインしてみる

今回作ったGoogle App Engineアプリを実行してみますと、下のような画面が表示されるはずです。ボタンは初回のみ表示されます。

表示されているログインボタンをクリックすると、下のようなアプリ承認画面が表示されます。


ユーザーがこの画面にある「承認」ボタンを使ってこのアプリの承認を行えます。ユーザーに承認されると先ほど定義したJavaScriptのコールバック関数が呼ばれます。

試しにクリックしてみてください。「ログイン失敗しました。」になるはずです。これはユーザー登録コントローラーをまだ作っていないからです。

では次回、このユーザー登録コントローラーとログイン後のトップページを作って行きたいと思います。