2020年6月14日

ReactのSPAアプリケーションでContextとHooksを使ってGoogle認証を実装する

ReactのSPAアプリケーションにおいて、ContextとHooksを使うことでGoogle認証の処理をラップして利用するというサンプルを作成しました。


Google Cloud Consoleでアプリケーションを登録する




OAuth consent screenを設定する  







OAuth client IDを作成する








Create React AppでReactアプリケーションを作成する


npx create-react-app project-name
cd project-name


public/index.html を編集する


WebアプリケーションでGoogle認証を利用するための最もシンプルなサンプルコードがこちらにあります。

Google Sign-In for Websites  |  Google Developers 

<html lang="en">
  <head>
    <meta name="google-signin-scope" content="profile email">
    <meta name="google-signin-client_id" content="YOUR_CLIENT_ID.apps.googleusercontent.com">
    <script src="https://apis.google.com/js/platform.js" async defer></script>
  </head>
  <body>
    <div class="g-signin2" data-onsuccess="onSignIn" data-theme="dark"></div>
    <script>
      function onSignIn(googleUser) {
        // Useful data for your client-side scripts:
        var profile = googleUser.getBasicProfile();
        console.log("ID: " + profile.getId()); // Don't send this directly to your server!
        console.log('Full Name: ' + profile.getName());
        console.log('Given Name: ' + profile.getGivenName());
        console.log('Family Name: ' + profile.getFamilyName());
        console.log("Image URL: " + profile.getImageUrl());
        console.log("Email: " + profile.getEmail());
        // The ID token you need to pass to your backend:
        var id_token = googleUser.getAuthResponse().id_token;
        console.log("ID Token: " + id_token);
      }
    </script>
  </body>
</html>

これを参考に public/index.htmlを編集します。

上のサンプルコードの中でReactアプリで必要になるのはGoogleのスクリプトを読み込んでいる行だけなので、その部分をコピーしてheadタグ内に挿入します。

    <script src="https://apis.google.com/js/platform.js"></script>

Googleのサンプルコードでは「async defer」という属性が付いていますが、Create React Appの場合これがあるとスクリプトが実行されるタイミングの関係で上手く動かないので削除しています。



.env.localファイルを作成する


次にプロジェクトのルートフォルダに「.env.local」 ファイルを作成して値を設定しておきましょう。

REACT_APP_CLIENTID=41702000-xxxxxxxxxxxxx.apps.googleusercontent.com

この環境変数の名前は、Create React Appの規約上「REACT_APP_」から始まる必要があるので注意してください。

ClientIdを環境変数に持たせておくことによって、本番用、ステージング用など、ビルド環境に応じて柔軟に変更することが出来るようになります。


src/google-auth.jsファイルを作成する


Google APIを実際に呼び出す際に使う関数をこのファイルにまとめておきます。

init(), signIn(), signOut()の3つの関数をエクスポートしています。
------


src/auth-state.jsファイルを作成する


上のgoogle-auth.jsに定義した関数をReactアプリ内で使うためのContextプロバイダーとフックを提供するファイルになります。

内部的にはuseReducerを使って認証状態を管理していますが、それはファイル内に隠蔽して外部へはAuthProviderコンポーネントとuseAuthStateフックをエクスポートしています。

useAuthStateフックからの戻り値は、認証状態を表す state オブジェクトとサインイン、サインアウト処理を呼び出すための関数を提供する actions オブジェクトの2要素配列となっています。

---
---


ここまで準備が出来れば、あとは

1. AuthProviderコンポーネントでアプリをラップする。
2. 任意のコンポーネント内でuseAuthStateフックを使って認証機能にアクセスする。

という形になります。


App.js
function App() {
  return (
    <AuthProvider>
      <div className="App">
        <header className="App-header">
          <h1>Google Auth React Examle</h1>
          <SignInOutButton />
        </header>
        <div className="App-main">
          <UserInfo />
        </div>
      </div>
    </AuthProvider>
  );
}


SignInOutButton.js
 
import React from 'react'; import { useAuthState } from './auth-state'; 
export function SignInOutButton() {
  const [state, actions] = useAuthState();
  const { isSignedIn } = state;
  const { signIn, signOut } = actions;
  if (isSignedIn === undefined) {
    return null;
  }
  return (
    <div>
      {isSignedIn ? (
        <button onClick={signOut}>Sign Out</button>
      ) : (
        <button onClick={signIn}>Sign In</button>
      )}
    </div>
  );
}




今回作成したアプリケーションのソースコードはこちらにあります。





以上、ReactのSPAアプリケーションにおいて、ContextとHooksを使ってGoogle認証の処理をラップするサンプルでした。



次回は、認証した後さらにGoogle Drive APIを使ってアプリケーションのデータを(バックエンドサーバー無しで)ブラウザから直接Google Driveに保存するということに挑戦したいと思います。