day2の課題は「ログイン機能を実装」です。
この辺の機能はfirebaseにどっぷり浸かる予定なので、指示通りにポチポチしていくことになります。
まずはfirebaseにprojectを作成し、アプリを追加します。
firebase上での操作はほぼ悩むことはなかったので省略。
途中でapi key等の情報が出てくるのでメモします。
nextjs
フロントサイドのコードを追加していきます。
まずは先ほどのKey等を.envファイルに保存します。
nextjsなのでNEXT_PUBLICの接頭辞を付与して変数を作成。フロントの呼び出し側のコードではビルド時にインライン展開されるようになります。
// .env.local
NEXT_PUBLIC_API_KEY=aaa
NEXT_PUBLIC_AUTH_DOMAIN=aaa.firebaseapp.com
NEXT_PUBLIC_PROJECT_ID=aaa
NEXT_PUBLIC_STORAGE_BUCKET=aaa3.appspot.com
NEXT_PUBLIC_MESSAGING_SENDER_ID=111
NEXT_PUBLIC_APP_ID=aaa
NEXT_PUBLIC_MEASUREMENT_ID=aaa
お次はfirebaseSDKの初期化です。
今回はサイト自体は静的サイトをデプロイして、動的な部分は全てCloud Functionsで行う予定なので、サーバサイドでの認証処理はありません。全部フロントでやります。
初期化を実行するメソッドをexportしておいて、nextjsの初期化時に呼び出すことにしました。
// firebase.ts
import { FirebaseApp, initializeApp } from 'firebase/app'
const firebaseConfig = {
apiKey: process.env.NEXT_PUBLIC_API_KEY,
authDomain: process.env.NEXT_PUBLIC_AUTH_DOMAIN,
projectId: process.env.NEXT_PUBLIC_PROJECT_ID,
storageBucket: process.env.NEXT_PUBLIC_STORAGE_BUCKET,
messagingSenderId: process.env.NEXT_PUBLIC_MESSAGING_SENDER_ID,
appId: process.env.NEXT_PUBLIC_APP_ID,
measurementId: process.env.NEXT_PUBLIC_MEASUREMENT_ID,
}
export const initializeFirebase = () => initializeApp(firebaseConfig)
フロントでログインユーザの情報を利用するためにAuthContextを定義します。
getAuth().currentUserをStateで管理して、Providerでどこからでも呼び出せるようにします。
import { getAuth, User } from 'firebase/auth'
import { ReactNode, createContext, useContext, useEffect, useState } from 'react'
export const AuthContext = createContext<{
user?: User | null
}>({})
export const AuthProvider = ({ children }: { children: ReactNode }) => {
const [user, setUser] = useState(() => getAuth().currentUser)
useEffect(() => {
getAuth().onAuthStateChanged(setUser)
}, [])
return <AuthContext.Provider value={{ user }}>{children}</AuthContext.Provider>
}
export const useAuth = () => useContext(AuthContext)
ちょっと余計なコードが混ざっていますが、アプリのRootで呼び出す箇所でinitializeFirebaseを呼び出して初期化しつつ、AuthProviderでchildrenをラップします。今回はMUIを利用しているのでthemeProviderもセットです。
'use client'
import { CssBaseline, ThemeProvider, createTheme } from '@mui/material'
import { initializeFirebase } from '../modules/firebase'
import { AuthProvider } from '../hooks/useAuth'
initializeFirebase()
const theme = createTheme({
palette: {
primary: {
main: '#fcba03',
},
},
})
export function MyApp({ children }: { children: React.ReactNode }) {
return (
<>
<CssBaseline />
<AuthProvider>
<ThemeProvider theme={theme}>{children}</ThemeProvider>
</AuthProvider>
</>
)
}
サインインとサインアウトのボタンは以下のようなコードを書きます。
今回はGoogleアカウントでのサインインのみ対応するため、GoogleAuthProviderを渡します。この辺は必要に応じて変えてください。サインアウトは特にProviderの指定は要りません。
<Button
variant="outlined"
onClick={() => signInWithRedirect(getAuth(), new GoogleAuthProvider())}
>
Sign In
</Button>
<Button
variant="outlined"
onClick={async () => {
await signOut(getAuth())
location.reload()
}}
>
ということで出来たサイトがこんな感じ。
MUIのAppBarにログアウトボタンがあるので、最終的にはそちらを利用する形に改修予定。今は機能だけ実装できれば細かいことは言いません。
コメント