#Next.js Authentication
#Overview
Authentication is essential for securing your application. Next.js supports multiple authentication approaches, including NextAuth.js, JWT, sessions, and more.
#NextAuth.js (Recommended)
#Installation
npm install next-auth#Basic Configuration
// app/api/auth/[...nextauth]/route.ts
import NextAuth from 'next-auth'
import GithubProvider from 'next-auth/providers/github'
import CredentialsProvider from 'next-auth/providers/credentials'
const handler = NextAuth({
providers: [
GithubProvider({
clientId: process.env.GITHUB_ID!,
clientSecret: process.env.GITHUB_SECRET!,
}),
CredentialsProvider({
name: 'Credentials',
credentials: {
email: { label: "邮箱", type: "email" },
password: { label: "密码", type: "password" }
},
async authorize(credentials) {
const user = await verifyUser(credentials)
if (user) {
return user
}
return null
}
})
],
pages: {
signIn: '/login',
},
callbacks: {
async jwt({ token, user }) {
if (user) {
token.id = user.id
}
return token
},
async session({ session, token }) {
session.user.id = token.id
return session
}
}
})
export { handler as GET, handler as POST }#Using Authentication
// app/profile/page.tsx
import { getServerSession } from 'next-auth'
import { redirect } from 'next/navigation'
export default async function Profile() {
const session = await getServerSession()
if (!session) {
redirect('/login')
}
return <div>欢迎,{session.user.name}</div>
}
// components/LoginButton.tsx
'use client'
import { signIn, signOut, useSession } from 'next-auth/react'
export default function LoginButton() {
const { data: session } = useSession()
if (session) {
return (
<button onClick={() => signOut()}>
退出
</button>
)
}
return (
<button onClick={() => signIn()}>
登录
</button>
)
}#JWT Authentication
#Creating JWT Utilities
// lib/jwt.ts
import jwt from 'jsonwebtoken'
const SECRET = process.env.JWT_SECRET!
export function signToken(payload: any) {
return jwt.sign(payload, SECRET, { expiresIn: '7d' })
}
export function verifyToken(token: string) {
try {
return jwt.verify(token, SECRET)
} catch {
return null
}
}#Login API
// app/api/login/route.ts
import { NextResponse } from 'next/server'
import { signToken } from '@/lib/jwt'
export async function POST(request: Request) {
const { email, password } = await request.json()
const user = await verifyCredentials(email, password)
if (!user) {
return NextResponse.json(
{ error: '凭据无效' },
{ status: 401 }
)
}
const token = signToken({ userId: user.id })
return NextResponse.json({ token, user })
}#Middleware Protection
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import { verifyToken } from '@/lib/jwt'
export function middleware(request: NextRequest) {
const token = request.cookies.get('token')?.value
if (!token) {
return NextResponse.redirect(new URL('/login', request.url))
}
const payload = verifyToken(token)
if (!payload) {
return NextResponse.redirect(new URL('/login', request.url))
}
return NextResponse.next()
}
export const config = {
matcher: ['/dashboard/:path*', '/profile/:path*']
}#Session Authentication
#Using Cookies
// app/api/login/route.ts
import { cookies } from 'next/headers'
import { NextResponse } from 'next/server'
export async function POST(request: Request) {
const { email, password } = await request.json()
const user = await verifyCredentials(email, password)
if (!user) {
return NextResponse.json({ error: '登录失败' }, { status: 401 })
}
const sessionId = await createSession(user.id)
cookies().set('session', sessionId, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
maxAge: 60 * 60 * 24 * 7 // 7 days
})
return NextResponse.json({ user })
}#Getting the Current User
// lib/auth.ts
import { cookies } from 'next/headers'
export async function getCurrentUser() {
const sessionId = cookies().get('session')?.value
if (!sessionId) {
return null
}
const session = await getSession(sessionId)
if (!session) {
return null
}
return session.user
}#Best Practices
#1. Protect API Routes
// lib/auth.ts
export async function requireAuth(request: Request) {
const token = request.headers.get('Authorization')?.split(' ')[1]
if (!token) {
throw new Error('未授权')
}
const payload = verifyToken(token)
if (!payload) {
throw new Error('令牌无效')
}
return payload
}
// app/api/posts/route.ts
import { requireAuth } from '@/lib/auth'
export async function POST(request: Request) {
try {
const user = await requireAuth(request)
// 创建文章
} catch (error) {
return NextResponse.json({ error: error.message }, { status: 401 })
}
}#2. Password Hashing
npm install bcryptimport bcrypt from 'bcrypt'
// 注册时加密密码
const hashedPassword = await bcrypt.hash(password, 10)
// 登录时验证密码
const isValid = await bcrypt.compare(password, user.hashedPassword)#3. Refresh Tokens
// app/api/refresh/route.ts
export async function POST(request: Request) {
const { refreshToken } = await request.json()
const payload = verifyToken(refreshToken)
if (!payload) {
return NextResponse.json({ error: '令牌无效' }, { status: 401 })
}
const newToken = signToken({ userId: payload.userId })
return NextResponse.json({ token: newToken })
}#Related Resources
Previous Chapter: Next.js State Management | Next Chapter: Next.js Database Integration