Next.js Middleware: Xây dựng xác thực và ủy quyền mạnh mẽ

Table of Contents
Xác thực và ủy quyền là nền tảng của bất kỳ ứng dụng web bảo mật nào. Trước đây, trong Next.js, việc bảo mật các tuyến đường có nghĩa là gói các thành phần trong Higher-Order Components (HOCs) hoặc thực hiện kiểm tra trong getServerSideProps trên cơ sở từng trang. Tuy nhiên, với sự trưởng thành của Next.js App Router và Edge Middleware, giờ đây chúng ta có một cách tiếp cận vượt trội hơn nhiều, tập trung và hiệu quả để xử lý bảo mật.
Vào năm 2026, Next.js Middleware chạy trên Edge, có nghĩa là các kiểm tra xác thực diễn ra cực kỳ gần với người dùng, trước khi một yêu cầu thậm chí còn đến máy chủ gốc của bạn. Bài viết này khám phá cách xây dựng các đường ống xác thực và ủy quyền mạnh mẽ, có khả năng mở rộng bằng cách sử dụng Next.js Middleware.
Tại sao lại dùng Middleware cho Xác thực?
Middleware cho phép bạn chặn một yêu cầu, kiểm tra một phiên hoặc mã thông báo hợp lệ và quyết định xem có cho phép yêu cầu đi qua, viết lại nó hay chuyển hướng người dùng hay không.
Lợi ích chính:
- Tập trung hóa: Bạn không còn cần phải phân tán logic xác thực trên hàng chục trang hoặc bố cục. Một tệp
middleware.tsduy nhất có thể bảo mật toàn bộ ứng dụng của bạn. - Hiệu suất: Chạy trên các môi trường thời gian chạy Edge (như Vercel Edge Functions hoặc Cloudflare Workers) có nghĩa là thời gian khởi động gần như bằng 0 và độ trễ tối thiểu. Việc kiểm tra diễn ra trước khi trang bắt đầu hiển thị.
- Bảo mật: Bằng cách chặn các yêu cầu chưa được xác thực tại Edge, bạn giảm tải cho máy chủ gốc và cơ sở dữ liệu của mình.
Luồng xác thực cơ bản
Kiểm tra và xem xét tải trọng JWT, tiêu đề yêu cầu và dấu thời gian hết hạn của bạn trong thời gian thực với bộ giải mã trình duyệt không rò rỉ của chúng tôi:
Hãy xem xét một triển khai tiêu chuẩn sử dụng JSON Web Tokens (JWTs) được lưu trữ trong cookie.
1. Thiết lập Middleware
Tạo một tệp middleware.ts tại thư mục gốc của dự án của bạn (hoặc trong thư mục src nếu bạn sử dụng nó).
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import { verifyJwtToken } from '@/lib/auth' // Your custom JWT verifier
export async function middleware(request: NextRequest) {
const token = request.cookies.get('auth-token')?.value
const isAuthPage = request.nextUrl.pathname.startsWith('/login') ||
request.nextUrl.pathname.startsWith('/register')
// 1. Check if token exists and is valid
const verifiedToken = token && (await verifyJwtToken(token).catch((err) => {
console.error('Failed to verify token', err)
}))
// 2. Redirect unauthenticated users away from protected routes
if (!verifiedToken) {
if (!isAuthPage && request.nextUrl.pathname.startsWith('/dashboard')) {
const loginUrl = new URL('/login', request.url)
loginUrl.searchParams.set('callbackUrl', request.nextUrl.pathname)
return NextResponse.redirect(loginUrl)
}
}
// 3. Redirect authenticated users away from auth pages
if (verifiedToken && isAuthPage) {
return NextResponse.redirect(new URL('/dashboard', request.url))
}
// 4. Pass the request through if all checks pass
return NextResponse.next()
}
// See "Matching Paths" below
export const config = {
matcher: ['/dashboard/:path*', '/login', '/register'],
}
2. Khớp đường dẫn (matcher)
Cấu hình matcher rất quan trọng. Nó cho Next.js biết các tuyến đường nào sẽ kích hoạt middleware. Chạy middleware trên mọi yêu cầu (bao gồm tài sản tĩnh và tuyến API) là không hiệu quả.
Bằng cách chỉ định ['/dashboard/:path*', '/login', '/register'], chúng tôi đảm bảo logic xác thực của chúng tôi chỉ chạy khi cần thiết.
Xử lý ủy quyền (Kiểm soát truy cập dựa trên vai trò - RBAC)
Xác thực hỏi "Bạn là ai?". Ủy quyền hỏi "Bạn được phép làm gì?". Khi người dùng được xác thực, chúng ta thường cần kiểm tra vai trò hoặc quyền của họ.
Chúng ta có thể dễ dàng mở rộng middleware của mình để xử lý RBAC.
// ... previous imports
import { verifyJwtToken } from '@/lib/auth'
export async function middleware(request: NextRequest) {
const token = request.cookies.get('auth-token')?.value
const verifiedToken = token && (await verifyJwtToken(token))
// ... standard auth checks
// Handle Authorization
if (verifiedToken) {
const userRole = verifiedToken.role // Assuming role is encoded in the JWT
// Protect admin routes
if (request.nextUrl.pathname.startsWith('/admin')) {
if (userRole !== 'ADMIN') {
// User is authenticated, but not authorized
return NextResponse.redirect(new URL('/unauthorized', request.url))
}
}
}
return NextResponse.next()
}
export const config = {
matcher: ['/dashboard/:path*', '/admin/:path*', '/login'],
}
Các phương pháp bảo mật tốt nhất trong Middleware
- Giữ cho nó nhẹ nhàng: Các môi trường thời gian chạy Edge có giới hạn về kích thước và thời gian thực thi. Không thực hiện các truy vấn cơ sở dữ liệu nặng trong middleware của bạn. Dựa vào các kiểm tra nhanh, không trạng thái như xác minh JWT.
- Sử dụng
josecho JWT Edge:jsonwebtokenNode.js tiêu chuẩn dựa vào các API mã hóa Node, không có sẵn trên Edge. Sử dụng một thư viện nhưjoseđể ký và xác minh mã thông báo trong middleware. - Cookie an toàn: Đảm bảo cookie xác thực của bạn được đặt với
HttpOnly,SecurevàSameSite=laxhoặcstrictđể ngăn chặn các cuộc tấn công XSS và CSRF. - Xử lý lỗi duyên dáng: Nếu xác minh mã thông báo thất bại (ví dụ: chữ ký hết hạn), hãy bắt lỗi một cách duyên dáng và chuyển hướng đến đăng nhập, thay vì ném một ngoại lệ không được xử lý gây ra lỗi 500.
Nâng cao: Truyền dữ liệu đến các thành phần máy chủ
Một thách thức phổ biến là: sau khi xác minh mã thông báo trong middleware, làm thế nào chúng ta có thể truyền dữ liệu người dùng đến các Thành phần máy chủ mà không cần xác minh lại mã thông báo?
Bạn có thể thay đổi tiêu đề yêu cầu trong middleware và đọc chúng trong các Thành phần máy chủ của bạn.
Trong Middleware:
if (verifiedToken) {
const requestHeaders = new Headers(request.headers)
requestHeaders.set('x-user-id', verifiedToken.userId)
return NextResponse.next({
request: {
headers: requestHeaders,
},
})
}
Trong Thành phần máy chủ (page.tsx):
import { headers } from 'next/headers'
export default function DashboardPage() {
const headersList = headers()
const userId = headersList.get('x-user-id')
return <div>Welcome User: {userId}</div>
}
Kết luận
Next.js Middleware cung cấp một lớp mạnh mẽ, được tối ưu hóa cho Edge để xử lý xác thực và ủy quyền. Bằng cách tập trung các kiểm tra này, bạn đơn giản hóa đáng kể hệ thống phân cấp thành phần của mình, cải thiện hiệu suất và tăng cường tư thế bảo mật tổng thể của ứng dụng. Khi kết hợp với JWT không trạng thái và khớp tuyến đường cẩn thận, nó tạo thành xương sống của một kiến trúc Next.js hiện đại.
Bạn cũng có thể thích
Free In-Browser Developer Tools
Clean AI CLI logs, build cron expressions, decode JWTs, and calculate chmod permissions offline.
Related Articles

TypeScript thôi là chưa đủ: Đảm bảo an toàn kiểu dữ liệu end-to-end với Zod trong Next.js
TypeScript biến mất khi runtime. Tìm hiểu lý do tại sao các kiểu tĩnh thất bại ở ranh giới API và Server Action của bạn, và cách Zod mang lại xác thực schema không thể sai sót và suy luận kiểu.
Read more
suppressHydrationWarning trong Next.js: Hướng dẫn sử dụng an toàn & gỡ lỗi đầy đủ
Hướng dẫn toàn diện về suppressHydrationWarning trong Next.js: sử dụng an toàn & gỡ lỗi đầy đủ với các ví dụ thực tế đã được kiểm chứng.
Read more
gRPC vs ConnectRPC: Microservices hiện đại và Protobuf gốc trình duyệt
Đánh giá kiến trúc gRPC vs ConnectRPC trong TypeScript và Go, khám phá streaming HTTP/1.1 vs HTTP/2, client trình duyệt không cần proxy Envoy và độ trễ RPC p99.
Read more