2013年2月 8日

OpenID/OAuth

YConnectで簡単ID連携!その1 ~ログインボタンの設置~

  • このエントリーをはてなブックマークに追加

 こんにちは、ID厨のくら(@kura_lab)です。

 みなさん「YConnect」をご存じでしょうか。OAuth 2.0OpenID Connectをサポートしたヤフーの新しい認証・認可のプロトコルなのです。YConnectを利用すると、Yahoo! JAPAN IDであなたのウェブサイトにログインできたり、ユーザーの登録情報を取得してサービスに利用できたりします。もちろん今までのOAuth 1.0のようにヤフーのWeb APIも利用することができます。

 YConnectをぜひみなさんにご利用していただきたいということで実際にログイン機能を実装してみようと思います。
 OAuth 2.0を基礎としているプロトコルなのでゼロから実装しても決して難しくはないのですが、YConnectといっしょに提供されている「YConnect PHP SDK」をつかって爆速で実装しましょう。

目的  :Yahoo! JAPANの認証(ログイン)機能の実装
対象  :PHP基礎レベル以上
所要時間:およそ30分
環境  :Apache + PHP 5.2.x 以降(curl、json関連パッケージが必要)

1. アプリケーションIDの発行

 はじめにYConnectのアプリケーションIDとシークレットを発行します。
https://e.developer.yahoo.co.jp/dashboard/へアクセスして「新しいアプリケーションを開発」を押してしてください。
 今回はPHPを使ってサーバー側で認証を行うのでアプリケーションの種類は「サーバーサイド」を選択してください。
 その他必須項目を入力してください。利用するスコープはユーザーの登録情報取得のみの場合には不要なので選択しなくてもOKです。確認の前にきちんとガイドライン(https://about.yahoo.co.jp/docs/info/terms/chapter1.html#cf5th)を読んでおきましょう。

アプリケーションIDの発行

 入力内容の確認後、登録ボタンを押すことでアプリケーションIDとシークレットが発行されます。
次に「アプリケーションの詳細」の「アプリケーション情報」タブのコールバックURLを追加します。

アプリケーション情報

 ユーザーはログイン画面、YConnectの同意画面表示後に、ここで指定したURLにリダイレクトされます。ドメインだけでなくフルパスを指定することに注意です。この指定先に認証を実装することにします。コールバックURLを指定したら更新ボタンのクリックを忘れないようにしてください。


2. PHP SDKの準備

 開発の準備をしましょう。
以下のURLからPHP SDKをダウンロードして任意の場所に展開してください。

 次にJSON Web TokenライブラリーのJWT.phpを以下のサイトからダウンロードして先ほど展開したlibディレクトリ下に配置してください。

 配置ができましたらlibディレクトリにPHPのパスを通して呼び出せるようにしてください。


3. ログインボタン設置

 Yahoo! JAPAN IDのログインボタンを設置します。以下から設置したいサイトにあわせてサイズを選びましょう。

 今回はこのサイズのボタンでこんな感じに配置しました。(このサイトは実在しません)

ログインボタン

 ボタンの配置だけでもID連携らしくなったとおもいます。ボタンのリンク先には認証を実装するPHPファイルを指定しておきます。

<a href="start.php">
  <img src="https://s.yimg.jp/images/login/btn/btnXSYid.gif" width="241" height="28" alt="Yahoo! JAPAN IDでログイン" border="0" />
</a>


4. IDトークンで認証

 ここからPHPで実装していきます。認証までの処理をサンプルコードで解説していきます。
まずはログインと同意のフローを実装していきます。以下のファイルはログインボタンのリンク先である「start.php」です。

<?php
// start.php

// YConnectライブラリ読み込み...(1)
require("lib/YConnect.inc");
 
// アプリケーションID, シークレット...(2)
$client_id     = "YOUR_APPLICATION_ID";
$client_secret = "YOUR_SECRET";
 
// コールバックURL...(3)
$callback_uri = "http://" . $_SERVER["SERVER_NAME"] . "/signup.php";
// リクエストとコールバック間の検証用のランダムな文字列を指定してください...(4)
$state = "44Oq44Ki5YWF44Gr5L+644Gv44Gq44KL77yB";
// リプレイアタック対策のランダムな文字列を指定してください...(5)
$nonce = "5YOV44Go5aWR57SE44GX44GmSUTljqjjgavjgarjgaPjgabjgog=";
// レスポンスタイプ...(6)
$response_type = OAuth2ResponseType::CODE_IDTOKEN;
// Scope...(7)
$scope = array(
    OIDConnectScope::OPENID,
    OIDConnectScope::PROFILE,
    OIDConnectScope::EMAIL,
    OIDConnectScope::ADDRESS
);
// display...(8)
$display = OIDConnectDisplay::DEFAULT_DISPLAY;
// prompt...(9)
$prompt = array(
    OIDConnectPrompt::DEFAULT_PROMPT
);
 
// クレデンシャルインスタンス生成
$cred = new ClientCredential( $client_id, $client_secret );
// YConnectクライアントのインスタンス生成
$client = new YConnectClient( $cred );
 
// デバッグ用ログ出力...(10)
$client->enableDebugMode();
 
// Authorizationエンドポイントにリクエスト...(11)
$client->requestAuth(
    $callback_uri,
    $state,
    $nonce,
    $response_type,
    $scope,
    $display,
    $prompt
);

 各パラメーターの初期化を行います。ログイン画面・同意画面の表示の制御やテンプレートの選択などを設定していきます。
 またユーザーの登録情報の設定もここで設定します。(登録情報の取得については次回のTechBlogで解説します)

(1) パスを通したlibディレクトリ内のYConnect.incを読み込みます。

(2) アプリケーションの詳細で発行されたアプリケーションIDとシークレットを指定します。サンプルなのでハードコーディングしていますが、これらの値は外部に流出すると悪用されてしまうおそれがあるので管理には十分注意してください。

(3) アプリケーションの登録時に指定したコールバックURLを設定してください。

(4) stateは、CSRF対策としてリクエスト時の値とコールバックURLのクエリに付加された値が同じあるかを検証するための値です。毎回リクエストするたびに予測されにくいランダムな文字列を生成してください。 stateの保存方法のひとつにCookieに発行しておく方法があります。その他にもPHPのセッションやHTML5のlocalStorageを利用する方法などもあります。

(5) nonceは、リプレイアタックの防止のために用いられます。毎回リクエストするたびにランダムな文字列を生成してください。後半のIDトークンの検証で必要になるので適宜保存してください。

(6) 認証にはIDトークンを利用するため、レスポンスタイプに「OAuth2ResponseType::CODE_IDTOKEN」をしていしてください。

(7) 今回のサンプルではユーザー識別子、プロフィール情報、メールアドレス、住所情報を取得するために全てのScopeを指定していますが、不要な情報の取得は避け、ウェブサイトの目的に合わせて必要最低限のScopeを指定するようにしてください。

(8) display(任意オプションで省略可)はデバイスに合わせて同意画面のテンプレートを出しわけるために指定します。デフォルトの「OIDConnectDisplay::DEFAULT_DISPLAY」を指定した場合、PC版のテンプレートが表示されます。スマートフォン版を表示したい場合は「OIDConnectDisplay::SMART_PHONE」を指定してください。

(9) prompt(任意オプションで省略可)はログイン画面、同意画面の表示を制御するためのパラメーターです。「OIDConnectPrompt::LOGIN」を指定するとログイン(パスワード再確認)表示を強制することができます。「OIDConnectPrompt::CONSENT」を指定すると同意画面表示を強制することができます。複数の条件を設定することができます。

続いてはログイン画面と同意画面へリダイレクトさせる処理です。 デバッグのときはYConnectClient::enableDebugMode()でログの出力を有効にしておくと便利です。

(10) デバッグログを有効にします。Apacheのログにデバッグのためのログが出力されます。

(11) パラメーターを設定してAuthorizationエンドポイントにリクエストします。displayとpromptは任意のオプションなので省略することができます。 内部の処理としてはLocationヘッダーでリダイレクトさせています。

 各パラメーターの詳細についてはPHPアプリ(Authorization Codeフロー)を参照してください。

 Authorizationエンドポイントへリダイレクトした後は以下のような同意画面が表示されます。設定したアプリケーション名やサイトURLが表示されています。アプリケーションへの許可には、Scopeで指定した項目が列挙されているのが確認できると思います。

同意画面

 ログインと同意のフローの後は、コールバックURLにリダイレクトされます。クエリに認可コードがついてくるので値をとりだしてIDトークンの取得と検証まで実装しましょう。以下のファイルはコールバックURLに登録した「signup.php」です。

<?php
// signup.php

//...前処理...
$client = new YConnectClient( $cred );
 
// 認可コードを取得...(1)
$code_result = $client->getAuthorizationCode( $state );
 
if( $code_result ) {
 
    try {
        // Tokenエンドポイントにリクエスト...(2)
        $client->requestAccessToken(
            $redirect_uri,
            $code_result
        );
    } catch ( OAuth2TokenException $e ) {
        if( $e->invalidGrant() ) {
            // 再度Authorizationエンドポイントへリクエスト...(3)
        }
    }
 
    try {
        // IDトークンを検証...(4)
        $client->verifyIdToken( $nonce );
        // アクセストークン、リフレッシュトークンを取得...(5)
        $accessToken  = $client->getAccessToken();
        $refreshToken = $client->getRefreshToken();
    } catch ( IdTokenException $e ) {
        // 認証失敗...(6)
        echo "Unauthorized";
    }
    // ユーザー識別子を取得...(7)
    $userId = $client->getIdToken();
}
// ログインセッションの発行など...(8)

 このサンプルでは取得したデータはセッションを使って保存していますが、実際に実装するときは開発環境に応じた保存方法を利用しましょう。
 保存の際にはアクセストークンやリフレッシュトークンなどが外部から読み取られないようにしないといけないので注意してください。

(1) クエリから認可コードを抽出します。引数のstateははじめにリクエストしたときにCookieなどに保存していた値を指定します。getAuthorizationCode()の内部でstateが一致しているか検証しています。発行された認可コードはアクセストークン、IDトークンを取得するために必要な値です。

(2) Tokenエンドポイントにリクエストしてアクセストークン、リフレッシュトークン、IDトークンの値を受け取ります。受け取ったトークンはYConnectClientクラスのプロパティーに保持されているのでgetメソッドで取得することができます。

(3) 「YConnectClient::requestAccessToken()」でリクエストに失敗した場合、例外が投げられます。

 YConnectの利用中に起こるものとして認可コードの有効期限切れによる例外があります。有効期限切れの判定は「OAuth2TokenException::invalidGrant()」で行います。
 有効期限が切れていた場合は、はじめのAuthorizationエンドポイントのリクエストからやり直してください。

(4) IDトークンの検証を行います。リクエスト時のnonceを引数に指定してください。

(5) IDトークンが正しく検証できた場合、YConnectClientクラスのプロパティーに保持されているアクセストークン、リフレッシュトークンを取得します。(このトークンの利用方法は次回詳しく解説します)

(6) 「YConnectClient::verifyIdToken()」で検証に失敗した場合、例外が投げられます。

(7) 復号化されたIDトークンのオブジェクトを取得します。このオブジェクトにはユーザー識別子が含まれおり、認証後のログインセッションやデータ管理のキーとして利用することもできます。

(8) IDトークンの検証が正常に行えた場合、ログインセッションを発行(通常はCookieとして発行)してログイン状態としてください。
ウェブサイトの用途に合わせてサイトのポリシーに合わせた長さの有効期限で自前のログインセッションを発行してください。

おわりに

 これであなたのウェブサイトもYahoo! JAPAN IDでログインできるようになりました。YConnectを利用することで、ウェブサイトでわずらわしいパスワードの管理を考える必要がなくなります。

 次回は引き続き「YConnect PHP SDK」をつかってユーザーの登録情報を取得する方法について解説します。


追記

2013年3月4日(月)

  • 同意画面のサンプル画像を追加しました。

Yahoo! JAPANでは情報技術を駆使して人々や社会の課題を一緒に解決していける方を募集しています。詳しくは採用情報をご覧ください。

  • このエントリーをはてなブックマークに追加