Chapter 07

Auth:ログイン認証とログアウト処理

masalib
masalib
2020.12.24に更新

ログインができたのでログイン認証とログアウト処理を作りたいと思います。

ログイン認証

ログイン認証をおこなっていないため、ログインしていない人も/dashboardにアクセスできます。
会員向けのサービスを作るためには認証が必要です。認証用のプロバイダーを作ります

/src/components/AuthFirebaseRoute.js
import React from "react"
import { Route, Redirect } from "react-router-dom"
import { useAuth } from "../contexts/AuthContext"

export default function AuthFirebaseRoute({ component: Component, ...rest }) {
  const { currentUser } = useAuth()

  return (
    <Route
      {...rest}
      render={props => {
        return currentUser ? <Component {...props} /> : <Redirect to="/login" />
      }}
    ></Route>
  )
}

react-router-domのRoute部分を自分用に書き換えています。詳しくは本家のサンプルを参照してください。

https://reactrouter.com/web/example/auth-workflow

なお、「 { component: Component, ...rest }」 部分ですがpropsで渡ってきた部分のComponentとそのほかの値に分解している。
Componentを出力らしいですが書いていて悲しいのですが本当に理解できていません・・・😢

詳しくは以下のstackoverflowを参考にしてください

https://stackoverflow.com/questions/43484302/what-does-it-mean-rest-in-react-jsx

三項演算子が嫌いな人は普通のIFでも動きます。

if (currentUser){
    return <Component {...props} />
} else {
   return <Redirect to="/login" />
}
//return currentUser ? <Component {...props} /> : <Redirect to="/login" />

ログイン認証をRouteにいれる

作った認証を追加したいと思います

/src/components/App.js
import React from "react";
import Signup from "./Signup";
import Home from "./Home";
import Login from "./Login";
import Dashboard from "./Dashboard";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import { AuthProvider } from "../contexts/AuthContext";
+ import AuthFirebaseRoute from "./AuthFirebaseRoute"; //ログイン認証

export default function App() {
  return (
    <Router>
      <AuthProvider>
        <Switch>
          <Route path="/signup" component={Signup} />
          <Route exact path="/" component={Home} />
          <Route path="/login" component={Login} />
+          <AuthFirebaseRoute path="/dashboard" component={Dashboard} />
-          <Route path="/dashboard" component={Dashboard} />
        </Switch>
      </AuthProvider>
    </Router>
  );
}

ログアウト処理追加

ログインに比べると簡単な処理ですが、サイトとしては必要な機能なので作ります

/src/contexts/AuthContext.js
import React, { useContext, useState, useEffect } from "react";
import { auth } from "../firebase";

const AuthContext = React.createContext();

export function useAuth() {
  return useContext(AuthContext);
}

export function AuthProvider({ children }) {
  const [currentUser, setCurrentUser] = useState();
  const [loading, setLoading] = useState(true);

  function signup(email, password) {
    return auth.createUserWithEmailAndPassword(email, password);
  }
  function login(email, password) {
    return auth.signInWithEmailAndPassword(email, password);
  }
+  function logout() {
+    return auth.signOut();
+  }
  const value = {
    currentUser,
    signup,
    login,
+    logout
  };

  useEffect(() => {
    // Firebase Authのメソッド。ログイン状態が変化すると呼び出される
    auth.onAuthStateChanged((user) => {
      setCurrentUser(user);
      setLoading(false);
    });
  }, []);

  return (
    <AuthContext.Provider value={value}>
      {!loading && children}
    </AuthContext.Provider>
  );
}

ログアウト処理追加(画面側)

ダッシュボードの画面に追加します

/src/components/Dashboard.js
+ import React, { useState } from "react";
+ import { Link, useHistory } from "react-router-dom";
+ import Button from "@material-ui/core/Button";
+ import { useAuth } from "../contexts/AuthContext";
- import React from "react";
- import { Link } from "react-router-dom";

const Dashboard = () => {
+   const { currentUser, logout } = useAuth();
+   const history = useHistory();
+   const [error, setError] = useState("");

+   async function handleLogout() {
+     setError("");
+     try {
+       await logout();
+       history.push("/");
+     } catch {
+       setError("Failed to log out");
+     }
+   }

  return (
    <div>
      Dashboard:
+       {error && <div style={{ color: "red" }}>{error}</div>}
+       <div>
+         <strong>Email:</strong> {currentUser.email}
+       </div>
+       <div>
+         <strong>ハンドル名:</strong> {currentUser.displayName}
+       </div>
      <h2>
        <Link to="/login">Login</Link>
      </h2>
      <h2>
        <Link to="/signup">signup</Link>
      </h2>
+       <Button color="primary" onClick={handleLogout}>
+         Logout
+       </Button>
    </div>
  );
};
export default Dashboard;

修正も簡単ですね。

終了時点のソース

この画面でもユーザーを作成とログインができます。
React Developer Toolsならユーザーが作成された事が確認できます

この時点のソースです

補足

  • ログインおよびSingUpの処理成功時にリダイレクト処理を追加しています。そちらは省いています。ソース上には反映しています。