Next.js + Capacitorによるクロスプラットフォームアプリの紹介 – ③Auth0のユニバーサルログインの実装

React

はじめに

Auth0のユニバーサルログインを使用したログインを実装する

page.tsx

以下のコードは、Next.js の App Router 構造(app ディレクトリ)で page.tsx ファイルを使用して、LoginComponent をクライアントサイドでのみレンダリングする実装です。/loginに遷移した時に実行されます。

'use client'

import dynamic from 'next/dynamic'

const LoginComponent = dynamic(
  () => import('./components/LoginComponent').then((module) => module.default),
  {
    ssr: false,
  }
)

export default function Login() {
  return (
    <>
      <LoginComponent />
    </>
  )
}

1. 'use client' ディレクティブ:

  • Next.js 14 では、'use client' ディレクティブを使用することで、このファイル内のコードがクライアントサイドでのみ実行されるように指示します。これにより、SSR(サーバーサイドレンダリング)ではなく、クライアントサイドでのみ動作します。

2. dynamic インポート:

  • dynamic 関数を使って LoginComponent動的にインポート しています。これは、コンポーネントを遅延ロードして、初期ロード時のパフォーマンスを改善するための Next.js の機能です。
  • ssr: false によって、サーバーサイドレンダリングが無効化されています。これにより、LoginComponent はサーバー側でレンダリングされず、クライアントサイドでのみレンダリングされます。

3. import('./components/LoginComponent').then((module) => module.default):

  • この部分は、LoginComponent がデフォルトエクスポートであることを前提にしています。LoginComponentdefault export されている場合、この方法で正しくインポートできます。
  • .then((module) => module.default) は、import 関数が Promise を返すため、モジュールがロードされた後に default エクスポートを取得します。

4. <LoginComponent />:

  • 動的にインポートされた LoginComponent をこの場所でレンダリングしています。LoginComponent がロードされると、<LoginComponent /> がクライアントサイドで表示されます。

5. 戻り値としての LoginComponent のレンダリング:

  • Login コンポーネント内で LoginComponent を使用しており、ページが表示された際に LoginComponent がレンダリングされます。この実装により、LoginComponent の読み込みがクライアントサイドで遅延して行われ、初期ロードを軽減します。

この構造は、特に クライアントサイドでのみ動作する認証フロー や、ユーザーインターフェースの動的な要素を含むコンポーネントに適しています。

  • パフォーマンス最適化: LoginComponent の動的インポートにより、ページ全体がロードされる前に必要なコンポーネントだけをロードすることができます。これは、初期ロード時間を短縮し、ユーザー体験を向上させるのに役立ちます。
  • サーバーサイドレンダリングの無効化: ssr: false によって、このコンポーネントはサーバーサイドではレンダリングされず、クライアントサイドでのみ動作します。

LoginComponent.tsx

以下のコードは、Auth0 の認証機能を用いて、ユーザーがログインしていない場合に Universal Login を表示し、Capacitor を利用したモバイルデバイスでのリダイレクト処理も考慮した実装です。ログイン機能がウェブとモバイルの両方で適切に動作するように設計されています。

'use client'

import { useAuth0 } from '@auth0/auth0-react'
import { useEffect } from 'react'
import { useRouter } from 'next/navigation'
import { App as CapApp } from '@capacitor/app'
import { Browser } from '@capacitor/browser'
import { getDeviceInfo } from '@/lib/utils' // デバイス情報を取得するユーティリティ関数

const LoginComponent = () => {
  const { loginWithRedirect, isAuthenticated, isLoading, handleRedirectCallback } = useAuth0()
  const router = useRouter()

  // デバイスのプラットフォームに基づいてリダイレクト処理を変更
  const handleLogin = async () => {
    const deviceInfo = await getDeviceInfo()

    if (deviceInfo.platform === 'web') {
      // ウェブブラウザ環境の場合、通常のリダイレクト
      loginWithRedirect()
    } else {
      // モバイルデバイスの場合、Capacitor ブラウザでリダイレクト
      loginWithRedirect({
        openUrl: async (url) => {
          await Browser.open({ url, windowName: '_self' })
        },
      })
    }
  }

  // モバイルアプリの場合のリダイレクトコールバック処理
  useEffect(() => {
    const handleMobileRedirect = async () => {
      const deviceInfo = await getDeviceInfo()

      if (deviceInfo.platform !== 'web') {
        // モバイルアプリでのリダイレクト処理を設定
        CapApp.addListener('appUrlOpen', async ({ url }) => {
          if (url.includes('state') && (url.includes('code') || url.includes('error'))) {
            await handleRedirectCallback(url)
            router.replace('/home') // ログイン後のダッシュボードページ
            await Browser.close() // モバイルブラウザを閉じる
          }
        })
      }
    }

    // クライアントサイドでのみ実行
    if (!isLoading && typeof window !== 'undefined') {
      if (isAuthenticated) {
        router.replace('/home')
      } else {
        handleLogin() // ログイン処理を実行
      }
      handleMobileRedirect() // モバイル用リダイレクト設定
    }
  }, [isAuthenticated, isLoading, handleRedirectCallback, router])

  if (isLoading) {
    return <div>Loading...</div> // 認証情報を確認中
  }

  return null // 認証後はリダイレクトされる
}

export default LoginComponent;

1. loginWithRedirect() の使用:

  • loginWithRedirect() は、Auth0 の Universal Login ページにユーザーをリダイレクトしてログインさせるために使用されます。ユーザーがログインしていない場合、このメソッドが呼び出され、Auth0 のホスティングされたログインページに移動します。

2. ウェブとモバイルのリダイレクト処理の違い:

  • ウェブブラウザ環境: deviceInfo.platform === 'web' の条件で、通常のリダイレクトが行われます。ここでは、loginWithRedirect() がデフォルトの挙動で Auth0 のログインページにリダイレクトします。
  • モバイル環境(Capacitor): モバイルデバイスでは、Capacitor Browser プラグインを使用して、ネイティブのブラウザウィンドウで Auth0 のログインページを開きます。openUrl のオプションを使って、Browser.open() でブラウザを開く処理が行われます。

3. useEffect でのリダイレクト処理:

  • useEffect フック内で、コンポーネントがクライアントサイドでマウントされた後に認証状態を確認し、必要に応じてログイン処理またはリダイレクトを実行します。
  • isAuthenticatedtrue であればユーザーはログイン済みなので、/home ページにリダイレクトされます。isAuthenticatedfalse の場合は、handleLogin() メソッドが実行され、ユーザーがログインしていないために Universal Login ページにリダイレクトされます。

4. モバイルでのリダイレクトコールバック処理:

  • モバイルアプリでのログイン完了後、Capacitor AppappUrlOpen イベントリスナーを使って、Auth0 のリダイレクト URL(statecode が含まれる)を処理します。
  • handleRedirectCallback() は、リダイレクトされた URL を処理して、ログインを完了させます。完了後にユーザーを /home にリダイレクトし、モバイルブラウザウィンドウを閉じます。

5. isLoading の状態管理:

  • isLoading は、認証情報がまだロード中かどうかを示します。認証の状態がまだ確認できていない場合は、Loading... テキストが表示され、認証処理が終わるまでユーザーに待機画面を表示します。
  • 認証状態が確認されると、適切なリダイレクト(loginWithRedirect または /home)が行われます。

参考

関連記事

カテゴリー

アーカイブ

Lang »