ランサーズ(Lancers)エンジニアブログ > PHP > GoogleOAuth2.0を使って、超簡単にユーザー情報を取得した話

GoogleOAuth2.0を使って、超簡単にユーザー情報を取得した話

blog_admin|2019年12月04日
PHP

ランサーズ Advent Calendar 2019 4日目の記事となります。

みなさんこんにちは。ランサーズでエンジニアとしてインターンをしている神谷(@Gunji Kamiya)です。

今回の記事では、タイトルにもある通り、GoogleOAuthを使った実装の話を書いていきたいと思います!

みなさんは「GoogleOAuth」という言葉を聞いたことあるでしょうか?

もしかしたら、耳にしたことがあるかもしれませんが、一応解説をしておくと。。

GoogleOAuthとは

GoogleOAuthとは、Googleのプラットフォームが提供しているOAuth認証のことです。

これにより、Googleが提供しているプラットフォーム上でユーザーの合意が簡単に取れ、セキュアにユーザーの権限などを受け渡しすることができます。

今回管理画面では、よりログインのスムーズに行うために、このGoogleOAuthを使って、ログイン機能を実装することになりました。

ランサーズの歴史を簡単に

ランサーズのメインプロダクトは、2008年12月にリリースされました。

それと同じ時期に管理画面も作られたようなので、もう10年以上の歴史があることになりますね。。

ユーザーが使っているメインプロダクトは、定期的にUIの変更があったりするのですが、管理画面は社内の人間しか使わないということもあり、当時のままです。

まさにThe 管理画面!!というイメージを想像してもらって大丈夫です(笑)

とはいえ、10年以上ランサーズの管理画面を支えてきたのは事実ですし、これからもずっと使われていく大切な一つのプロダクトです。

これから責任を持って、使いやすく、みんなから好かれるような管理画面にしてあげるからね(´∀`*)

GoogleOAuthには世界中に豊富なライブラリが存在

さて、Googleログイン機能実装に取り組んでいきたいところだったのですが、ここで問題が。。

「やり方がわからない!!」という問題です。

まあこれは、初心者や経験者関係なくあるものですよね。

誰にでも初めてはあるものですし、今のご時世、インターネットに検索キーワードを入れれば簡単に答えにたどり着くことができるはずです。

検索をしてみると、さすがGoogleですね。

たくさんのドキュメントが用意されていました!

ただほとんどすべてが英語ベース!!

よく考えてみれば当たり前なことなのですが、これも良い経験なので頑張ってやってみましょう!

ライブラリをインストール

まずは、GoogleOAuthの実装に必要なライブラリをインストールしていきます。

ランサーズでは、CakePHPというフレームワークを使っているので、Composer経由でインストールします。

Google-Api-PHP-Clientのインストール

$ composer require google/apiclient:"^2.*"

GoogleSDKのインストール

$ composer require google/cloud:"^0.*"

これらのライブラリをインストールすることで、Googleサービス内の情報にアクセスするための機能を入れることができます。

しかし、これだけでは動きません!!

これとは別に、ユーザーを識別するための認証情報が必要になります。

Google Developers Consoleにログインし、対象のプロジェクトから「認証情報を作成」を押してください。

プルダウンが表示されるので、「OAuthクライアントID」を選択し、名前や制限事項などを設定してください。

その後、認証情報をJSON形式でダウンロードできるので、それもしておきましょう!!

認証情報を設置

アプリケーション側から認証情報を利用するために、特定のディレクトリにJSONファイルを設置します。

僕はこんな感じでディレクトリにJSONファイルを設置しました。

 README.md
 bin
 composer.json
 composer.lock
 composer.phar
 config
  |-- adminlte.php
  |-- app.php
  |-- bootstrap.php
  |-- routes.php
  |-- google_client_secret.json ←←← Googleの認証情報を設置
 logs
 phpunit.xml.dist
 plugins
 src
 tests
 tmp
 vendor
 webroot

JSONファイルはわかりやすいようにリネームして使用すると良いと思います。

ちなみに認証情報は次のようなデータが入っています。

{
	"web": {
		"client_id": "********************************************.apps.googleusercontent.com",
		"project_id": "**************",
		"auth_uri": "https://accounts.google.com/o/oauth2/auth",
		"token_uri": "https://oauth2.googleapis.com/token",
		"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
		"client_secret": "************************"
	}
}

ログインアクション

ここからは実際にソースコードに記載する実装を書いていきます。

僕の場合は特定のメソッドにログインアクションを実装していきました。

それがこちらです↓


        // オブジェクトを生成
        $client = new Google_Client();

        // 認証情報が記載されているJSONファイルを読み込む(必須)
        $client->setAuthConfig(__DIR__ . '/../../config/google_client_secret.json');

        // リダイレクト先に `authGoogle`メソッドに指定(必須)
        $client->setRedirectUri('https://' . $_SERVER['HTTP_HOST'] . '/users/authGoogle');

        // アクセスのスコープを定義(必須)
        $client->addScope("https://www.googleapis.com/auth/userinfo.email");

        // ユーザーのオフライン時にアクセストークンを更新できるように指定(推奨)
        $client->setAccessType('offline');

        // アクセストークンの増分を許可(オプション)
        $client->setIncludeGrantedScopes(true);

ここでは、Google認証を行うために必要な設定をしています。

それぞれの細かい詳細はこちらを参考にしてください。
Google OAuth2.0

その後、Googleへログイン処理を行うための処理を実装していきます。

GoogleOAuthでは、リダイレクト時に正常なアクセスかどうかを判別するために、トークンを設定できます。

以下では、そういったセキュアな設定も行なっています。


        // 偽造防止のためにトークンを指定
        $state = substr(base_convert(hash('sha256', uniqid()), 16, 36), 0, 40);
        $session->write('google.stateToken', $state);
        $client->setState($state);

        // GoogleのOAuth2.0サーバーへリクエストを行うためのURLを生成する
        $auth_url = $client->createAuthUrl();
        header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));

Googleオブジェクトの凄いところなのですが、リクエストのためのURLなどの生成が非常に簡単にできるんですよね。

URLを格納した変数を確認してみると、きちんと設定した情報をもとに長いURLが生成されていました。

https://accounts.google.com/o/oauth2/auth?response_type=code&access_type=offline&client_id=********************************************.apps.googleusercontent.com&redirect_uri=https*******************.jp%2Fusers%2FauthGoogle&state=21awgk049068gcwkwcsokgk4okkgsowogwgckk8c&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&approval_prompt=auto&include_granted_scopes=true

これらの手順を踏むと、画面は勝手にGoogleログインのページへ遷移することになります。

コールバック先での処理

ここからはGoogleの認証画面を経て、コールバックしてきた先の処理を実装していきます。

先ほどにも書きましたが、ログインなどの処理は正常なリクエストかどうかをきちんと確認すべきなので、そういった点を考慮していきます。


        // 正常なリクエストではなかった場合の処理
        if ($_GET['state'] !== $session->read('google.stateToken')) {
            // Googleログインに失敗した場合は `/`にリダイレクトし、処理を終了させる
            $redirect_uri = 'https://' . $_SERVER['HTTP_HOST'] . '/';
            header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
            exit;
        }
        // 認証トークンを変数に格納
        $code = $_GET['code'];
        // 認証トークンを元にアクセストークンを生成
        $client->authenticate($code);
        // 後ほどユーザー情報を取得するためにセッションに保存
        $session->write('google.access', $client->getAccessToken());
        $redirect_uri = 'https://' . $_SERVER['HTTP_HOST'] . '/users/googleLogin';
        header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
        $client->setAccessToken($session->read('google.access.access_token'));

現在の状況は、アクセストークンを控えている状態です。

コメントにも記載されていますが、後ほどユーザー情報を取得するために、セッションにアクセストークンを保存します。

超簡単にユーザー情報を取得

さて、ここまで来ればあとはユーザー情報を取得するだけです。

タイトルにもある通り、超簡単に取得できるので、ご安心ください(笑)


        // アクセストークンをもとにGoogleのユーザーデータを取得
        $googleUser = json_decode(
            file_get_contents('https://www.googleapis.com/oauth2/v1/userinfo?' . 'access_token=' . $session->read('google.access.access_token'))
        );

これだけです!

この1行だけで、次のようなユーザー情報を取得することができるのです!

(
    [id] => 000000000000000000000
    [email] => test.lancers@lancers.co.jp
    [verified_email] => 1
    [name] => テスト ランサーズ
    [given_name] => ランサーズ
    [family_name] => テスト
    [picture] => https://sdl-stickershop.line.naver.jp/stickershop/v1/product/1348144/iphone/main@2x.png
    [locale] => ja
    [hd] => lancers.co.jp
)

あとはこれらの情報をもとにログイン処理をすれば、簡単にGoogleログイン機能を作ることができます!

まとめ

今回は、Googleのライブラリを使ってユーザー情報を超簡単に取得して見ました!

それによって、スムーズに管理画面へログインをすることができるようになりました。

英語ベースのドキュメントを読み解きながら実装していくのは大変でしたが、ものすごく良い経験になりました。

今後、そういった実装があったとしても、臆することなく、突き進んでいきたいと思います!

Advent Calendar 4日目でした!!(忘れてた笑)

Lancers(ランサーズ) Advent Calendar 2019

参考ソース

googleapis/google-api-php-client
Google | OAuth2