做法
建立專案。
| 12
 
 | npx create-next-app@latestcd next-auth-example
 
 | 
安裝依賴套件。
實作
建立 Provider
新增 components/Provider.js 檔。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | 'use client';
 import { SessionProvider } from 'next-auth/react';
 
 export default function Provider({ children }) {
 return (
 <SessionProvider>
 {children}
 </SessionProvider>
 );
 }
 
 | 
修改 layout.js 檔。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 
 | import './globals.css'import { Inter } from 'next/font/google'
 import Provider from '@/components/Provider'
 
 const inter = Inter({ subsets: ['latin'] })
 
 export const metadata = {
 title: 'Create Next App',
 description: 'Generated by create next app',
 }
 
 export default function RootLayout({ children }) {
 return (
 <html lang="en">
 <body className={inter.className}>
 <Provider>
 {children}
 </Provider>
 </body>
 </html>
 )
 }
 
 | 
建立 API
新增 app/api/auth/[...nextauth]/route.js 檔。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 
 | import NextAuth from 'next-auth';import CredentialsProvider from 'next-auth/providers/credentials';
 
 const handler = NextAuth({
 pages: {
 signIn: '/sign-in',
 },
 providers: [
 CredentialsProvider({
 async authorize({ email, password }) {
 if (email === '[email protected]' && password === 'password') {
 return { token: 'token', email };
 }
 throw new Error('Invalid credentials');
 },
 }),
 ],
 callbacks: {
 async jwt({ token, user }) {
 if (user) {
 token.accessToken = user.token;
 }
 return token;
 },
 async session({ session, token }) {
 session.accessToken = token.accessToken;
 return session;
 },
 },
 });
 
 export { handler as GET, handler as POST };
 
 | 
建立 UI
修改 app/page.js 檔。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | 'use client';
 import { useRouter } from 'next/navigation';
 import { useEffect } from 'react'
 
 export default function Home() {
 const router = useRouter();
 useEffect(() => {
 router.push('/sign-in');
 }, []);
 return (
 <div />
 );
 }
 
 | 
新增 app/dashboard/page.js 檔。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 
 | 'use client';
 import { signOut, useSession } from 'next-auth/react';
 import { redirect } from 'next/navigation';
 
 export default function Dashboard() {
 const { data: session } = useSession();
 
 console.log('session', session);
 
 return (
 <>
 <button
 type="button"
 onClick={() => signOut()}
 >
 Sign Out
 </button>
 </>
 );
 }
 
 | 
新增 app/sign-in/page.js 檔。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 
 | 'use client';
 import { signIn } from 'next-auth/react';
 import { useRouter } from 'next/navigation';
 import { useState } from 'react';
 
 export default function SignIn() {
 const router = useRouter();
 
 const [email, setEmail] = useState('[email protected]');
 const [password, setPassword] = useState('password');
 
 const submit = async (e) => {
 e.preventDefault();
 const result = await signIn('credentials', {
 email,
 password,
 redirect: false,
 });
 console.log(result);
 if (result.error) {
 alert(result.error);
 return;
 }
 router.push('/dashboard');
 };
 
 return (
 <>
 <form onSubmit={submit}>
 <input
 type='text'
 placeholder="Email"
 defaultValue={email}
 onChange={(e) => setEmail(e.target.value)}
 />
 <input
 type="password"
 placeholder="Password"
 defaultValue={password}
 onChange={(e) => setPassword(e.target.value)}
 />
 <button
 type="button"
 onClick={submit}
 >
 Sign In
 </button>
 </form>
 </>
 );
 }
 
 | 
新增 app/sign-out/page.js 檔。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 
 | 'use client';
 import { signOut, useSession } from 'next-auth/react';
 import { useEffect } from 'react';
 import { useRouter } from 'next/navigation';
 
 export default function SignIn() {
 const router = useRouter();
 const { data: session } = useSession();
 
 useEffect(() => {
 (async () => {
 if (session) {
 await signOut({
 redirect: false,
 });
 }
 router.push('/sign-in');
 })();
 }, [router, session]);
 
 return (
 <div />
 );
 }
 
 | 
建立 Middleware
新增 .env 檔。
新增 middleware.js 檔。
| 12
 3
 4
 5
 6
 7
 
 | export { default } from 'next-auth/middleware';
 export const config = {
 matcher: [
 '/((?!api|sign-up|sign-in|forgot-password|sign-out|_next|.*\\..*|$).*)',
 ],
 };
 
 | 
啟動
啟動。
前往 http://localhost:8080 瀏覽。
程式碼
參考資料