0Pricing
React Academy · レッスン

保護されたルートとAuth Guard

wrapper componentsまたはloaderベースのguardを使い、未認証ユーザーをログインページへリダイレクトします。

「保護されたルートとAuth Guard」はCoddyKit上の無料React Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはReact Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 React Academyコースには全4レッスンが含まれています。

ルートを保護する理由

ダッシュボード、プロフィール、管理画面などのページは、認証済みのユーザーだけがアクセスできるようにする必要があります。React Router では、ラッパーコンポーネントとローダーベースのガードという2つの方法を利用できます。

認証状態の形

まず、ユーザーがログインしているかどうかをコンポーネントから確認できる認証コンテキストを用意します。

const AuthContext = React.createContext(null);

function AuthProvider({ children }) {
  const [user, setUser] = useState(null);
  const login = async (creds) => { const u = await apiLogin(creds); setUser(u); };
  const logout = () => setUser(null);
  return (
    <AuthContext.Provider value={{ user, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
}

export const useAuth = () => useContext(AuthContext);

ラッパーコンポーネントによるガード

認証状態を確認し、ユーザーが認証されていない場合はログインへリダイレクトする PrivateRoute コンポーネントを作成します。

import { Navigate, Outlet } from 'react-router-dom';

function PrivateRoute() {
  const { user } = useAuth();
  if (!user) return <Navigate to="/login" replace />;
  return <Outlet />;
}

// Usage in router:
{ element: <PrivateRoute />, children: [
  { path: '/dashboard', element: <Dashboard /> },
]}

リダイレクト先 URL の保持

ログイン後にユーザーを元のページへ戻せるよう、アクセスしようとした URL を保存します。Navigate コンポーネントの state を介して渡します。

function PrivateRoute() {
  const { user } = useAuth();
  const location = useLocation();
  if (!user) {
    return <Navigate to="/login" state={{ from: location }} replace />;
  }
  return <Outlet />;
}

// In login handler:
const location = useLocation();
const from = location.state?.from?.pathname || '/';
navigate(from, { replace: true });

ローダーベースのガード(Data Router)

Data Router API では、ルートの loader に認証チェックを追加します。ユーザーが認証されていない場合は redirect を throw します。

import { redirect } from 'react-router-dom';

function requireAuth() {
  const token = localStorage.getItem('token');
  if (!token) throw redirect('/login');
  return token;
}

const router = createBrowserRouter([
  {
    path: '/dashboard',
    loader: requireAuth,
    element: <Dashboard />,
  },
]);

ロールベースのガード

ガードを拡張してロールも確認します。ユーザーが必要なロールを持っていない場合は、権限のないユーザー向けのページにリダイレクトします。

function AdminRoute() {
  const { user } = useAuth();
  if (!user) return <Navigate to="/login" replace />;
  if (user.role !== 'admin') return <Navigate to="/unauthorized" replace />;
  return <Outlet />;
}

認証チェック中の読み込み状態

認証状態が非同期に読み込まれる場合(サーバーから取得する場合など)は、チェックが完了するまでスピナーを表示します。これにより、ログインページが一瞬表示されるのを防げます。

function PrivateRoute() {
  const { user, isLoading } = useAuth();
  if (isLoading) return <Spinner />;
  if (!user) return <Navigate to="/login" replace />;
  return <Outlet />;
}

複数のルートをまとめて保護する

保護対象のすべてのルートを1つの PrivateRoute ラッパーの下にまとめると、各ルートに個別にガードを記述せずに済みます。

const router = createBrowserRouter([
  { path: '/login', element: <Login /> },
  {
    element: <PrivateRoute />,
    children: [
      { path: '/dashboard', element: <Dashboard /> },
      { path: '/profile', element: <Profile /> },
      { path: '/settings', element: <Settings /> },
    ],
  },
]);

トークンの有効期限切れへの対応

ガード内またはグローバルインターセプターでトークンの有効期限を確認します。トークンの期限が切れたらユーザーをログアウトさせ、ログインへリダイレクトします。

function isTokenValid(token) {
  const payload = JSON.parse(atob(token.split('.')[1]));
  return payload.exp * 1000 > Date.now();
}

function requireAuth() {
  const token = localStorage.getItem('token');
  if (!token || !isTokenValid(token)) throw redirect('/login');
  return token;
}

リフレッシュトークンのフロー

401 の発生時にリダイレクトする前に、トークンの更新を試みます。更新にも失敗した場合だけログインへリダイレクトします。

async function requireAuth() {
  let token = localStorage.getItem('token');
  if (!token || isExpired(token)) {
    token = await refreshToken();
    if (!token) throw redirect('/login');
    localStorage.setItem('token', token);
  }
  return token;
}

再読み込み後も認証状態を保持する

認証トークンを localStorage または HttpOnly Cookie に保存します。アプリの読み込み時に、保護されたルートをレンダリングする前に認証状態を復元します。

理解度チェック

React Router でローダーベースの認証ガードを使う場合、認証されていないユーザーをリダイレクトするには何を throw すべきですか?

まとめ

<Outlet /> を使用する PrivateRoute ラッパー、または redirect() を throw するローダーでルートを保護します。ナビゲーション状態に目的の URL を保持し、画面のちらつきを防ぐために読み込み状態を処理します。また、保護対象のルートをまとめて重複を避けます。

よくある質問

「保護されたルートとAuth Guard」レッスンは無料ですか?

はい。「保護されたルートとAuth Guard」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、React Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 React Academyコースには全4レッスンが含まれています。

「保護されたルートとAuth Guard」で何を学びますか?

wrapper componentsまたはloaderベースのguardを使い、未認証ユーザーをログインページへリダイレクトします。 ブラウザで直接実行するハンズオンコードでReact Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

React Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのReact Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「保護されたルートとAuth Guard」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このReact Academyレッスンでコードを書いて実行できますか?

はい。すべてのReact Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. ネストしたルートとOutletレイアウト
  2. LoadersとActions(Data Router API)
  3. 保護されたルートとAuth Guard
  4. URL Search ParamsによるState管理
← React Academyに戻る