2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

React, Firebase 使った Googleアカウント連携したログインをやってみる

Last updated at Posted at 2023-12-06

React, Firebase を使って Googleアカウント使ってのログイン機能をつくってみる
Google アカウント使ったログインに関する処理は一つのモジュール AuthContext.js にまとめてみました
useContext 使って全体でステータス管理できるようにしてる感じです
実施した環境とざっくり手順はこんなかんじ

  • 実施した環境
    • Windows11
    • node v18.17.1
    • React v18.2.0
    • firebase v10.7.1
  • ざっくり手順
    • Firebase ログイン・アプリ利用準備
    • React から Firebase 使ったログイン機能作成

あと完成したやつは github においてます(Firebase の定義情報は各自の値で更新が必要)
https://github.com/sueasen/my-app-googleauth/tree/main

Firebase ログイン・アプリ利用準備

  1. Firebase のサイトにアクセス
    https://firebase.google.com/
  2. [使ってみる] をクリック → Google ログイン(ログイン入力画面は割愛)
    image.png
  3. [プロジェクトを作成] をクリック
    image.png
  4. プロジェクト情報を以下のように設定しプロジェクト作成 → 準備できたら続行
    image.png
  5. [Authentication] をクリック → 始める
    image.png
  6. 追加のプロバイダを Google にして以下のように設定して [保存] をクリック
    image.png
  7. Firebase をアプリ利用追加の [ウェブアイコン] をクリック
    ※Firebase SDK の追加にある firebaseConfig はReactから使う情報になります
    image.png

React から Firebase 使ったログイン機能作成

  1. プロジェクトを作成する

    こちらを参考に実施(以降は参考にしたやつをベースに進めます)
    https://qiita.com/sueasen/items/fe63a1693b2057b29d84

  2. Firebase, heroicons をインストール

    npm i firebase @heroicons/react
    
  3. src 直下に contexts ディレクトリ作成

    ディレクトリ作るの忘れると以降の import でパスがずれます

  4. src/contexts 直下に AuthContext.js 作成

    firebaseConfig の定義情報 (13行目~) は Firebase のアプリ利用で取得した値を使用
    設定する値は Firebase にログインしてプロジェクトの設定から確認できます

AuthContext.js
import { initializeApp } from 'firebase/app';
import {
  getAuth,
  GoogleAuthProvider,
  signInWithPopup,
  signOut,
} from 'firebase/auth';
import { useEffect, useState } from 'react';
import { createContext, useContext } from 'react';

// Context生成(ログインに関する情報を管理)
const AuthContext = createContext();
// firebase の定義情報(各値はFirebaseのアプリ利用で取得した値を使用する)
const firebaseConfig = {
  apiKey: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
  authDomain: 'xxxxxxxxxx.firebaseapp.com',
  projectId: 'xxxxxxxxxx',
  storageBucket: 'xxxxxxxxxx.appspot.com',
  messagingSenderId: '888888888888',
  appId: '1:888888888888:web:xxxxxxxxxxxxxxxxxxxxxxxxx',
};

// firebase, GoogleAuth 初期設定
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const provider = new GoogleAuthProvider();

// AuthContextProvider (Provider)
export const AuthContextProvider = ({ children }) => {
  // ログインユーザ
  const [loginUser, setLoginUser] = useState();

  // 起動時ログイン処理(既にログインしてる場合, ユーザ設定)
  useEffect(() => {
    // auth 初期化時にログインユーザ設定
    auth.onAuthStateChanged((user) => setLoginUser(user));
  }, []);

  // ログイン処理
  const login = async () => {
    // Google ログインのポップアップ表示して認証結果取得
    const result = await signInWithPopup(auth, provider);
    // 認証結果より user 設定
    setLoginUser(result.user);
  };

  // ログアウト処理
  const logout = async () => {
    await signOut(auth);
    setLoginUser(null);
  };

  // ログイン情報設定したProvider
  return (
    <AuthContext.Provider
      value={{
        loginUser,
        login,
        logout,
      }}
    >
      {children}
    </AuthContext.Provider>
  );
};

// AuthContextConsumer (useContext) # Provider で囲った範囲で使う必要あり
export const AuthContextConsumer = () => {
  return useContext(AuthContext);
};

5.src 直下の App.js を修正

  • AuthContextProvider の import 追加

  • コンポーネント返してるところの全体を AuthContextProvider で括る

    App.js
    import { appRouter } from './pages/AppRouter';
    import { AuthContextProvider } from './contexts/AuthContext';
    import Home from './pages/Home';
    import Page1 from './pages/Page1';
    import Page2 from './pages/Page2';
    import './App.css';
    
    // ページ情報を定義して appRouter に設定
    const pages = [
      { key: 'Home', path: '/', element: <Home /> },
      { key: 'Page1', path: '/page1', element: <Page1 /> },
      { key: 'Page2', path: '/page2', element: <Page2 text="text sample" /> },
    ];
    const router = appRouter(pages);
    
    const App = () => {
      return (
        <AuthContextProvider>
          {router.navbarLink}
          {/* 位置調整で main で括る */}
          <main>{router.browserRouter}</main>
        </AuthContextProvider>
      );
    };
    
    export default App;
    

6.src/pages 直下に LoginUser.js を作成

LoginUser.js
import { UserCircleIcon } from '@heroicons/react/24/solid';
import { AuthContextConsumer } from '../contexts/AuthContext';

const LoginUser = () => {
  // AuthContextConsumer からログインユーザ、ログイン・ログアウト処理取得
  const { loginUser, login, logout } = AuthContextConsumer();
  return (
    <>
      <div className="user_info">
        <UserCircleIcon className="user_icon" />
        <p className="user_name">
          {loginUser ? loginUser.displayName : 'ゲスト'}
        </p>
        <button className="login_btn" onClick={loginUser ? logout : login}>
          {loginUser ? 'logout' : 'login'}
        </button>
      </div>
    </>
  );
};
export default LoginUser;

7.src 直下の App.css を修正

  • LoginUser で設定したクラスに対してのスタイルを追記

    App.css
    .user_info {
        position: fixed;
        right: 0;
        top: 0;
        height: var(--height-navbar);
        display: flex;
        align-items: center;
        color: #ddd;
        font-size: 14px;
        letter-spacing: 1px;
    
        & .user_icon {
            height: calc(var(--height-navbar) - 10px);
        }
    
        & .user_name {
            margin: 0 5px;
            width: 80px;
        }
    
        & .login_btn {
            height: calc(var(--height-navbar) - 20px);
            width: 80px;
            margin: 0 5px;
            border-radius: 25px;
            color: #ddd;
            background: #1e1d1c;
            text-transform: uppercase;
        }
    
        & .login_btn:hover {
            opacity: 0.5;
        }
    }
    

8.src/pages 直下の AppRouter.js を修正

  • LoginUser のインポート追加
  • links (ヘッダーメニュー部) の最後に LoginUser を追加
AppRouter.js
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import LoginUser from './LoginUser';

export const appRouter = (pages) => {
  const router = () => {
    return (
      <>
        <BrowserRouter basename={process.env.PUBLIC_URL}>
          <Routes>
            {pages.map((p) => (
              <Route key={p.key} path={p.path} element={p.element} />
            ))}
          </Routes>
        </BrowserRouter>
      </>
    );
  };
  // タグ, クラスなど追加
  const links = () => (
    <header className="header">
      <div className="navtext-container">
        <div className="navtext">title</div>
      </div>
      <input type="checkbox" className="menu-btn" id="menu-btn" />
      <label htmlFor="menu-btn" className="menu-icon">
        <span className="navicon"></span>
      </label>
      <ul className="menu">
        {pages.map((p) => (
          <li key={p.key}>
            <a href={`${process.env.PUBLIC_URL}${p.path}`}>{p.key}</a>
          </li>
        ))}
      </ul>
      <LoginUser />
    </header>
  );
  return {
    browserRouter: router(),
    navbarLink: links(),
  };
};

9.実行確認

起動して [ログイン] クリック → Google認証 → ログイン成功(ユーザ名表示)でOK
※Google認証のポップアップ出てこない時はポップアップブロックを解除

image.png

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?