Next.js中客户端如何借助Http-only Cookie实现认证请求?
之前在CRA项目里,JWT存储在localStorage中,可直接添加到请求头Authorization: 'Bearer ...'里完成认证。现在按照Next.js的安全推荐,把令牌存在Http-only Cookie中,但客户端创建的请求实例(如axios、RTK Query)无法直接读取这个Cookie,请问如何正确代表已认证用户发送请求?
附登录API路由代码(api/auth/login/route.ts):
import { NextResponse } from 'next/server'; import axios from 'axios'; export async function POST(request: Request) { const { token } = await request.json(); try { const { data }: { data: OAuthResponse } = await axios.post( `${process.env.NEXT_PUBLIC_AXIOS_BASE_DEV_URL}auth/by-google`, { token } ); const response = NextResponse.json({ success: true }); response.cookies.set('auth_token', data.token, { httpOnly: true, secure: true, maxAge: 30 * 24 * 60 * 60, path: '/', }); return response; } catch (error) { return NextResponse.json( { message: 'Authorization failed' }, { status: 401 } ); } }
附RTK Query切片代码:
export const authApi = createApi({ reducerPath: 'api/auth', baseQuery: ..., endpoints: (build) => ({ loginWithGoogle: build.mutation<OAuthResponse, OAuthRequest>({ query: (body) => ({ url: 'auth/by-google', method: 'POST', body, }), }), fetchMe: build.query<OAuthResponse, void>({ query: () => ({ url: 'auth/me', method: 'GET', }), }), }), });
不想使用next-auth这类第三方库,希望了解Next.js原生实现方式。
解决方案
方案1:通过Next.js API路由代理请求(推荐)
Http-only Cookie仅能被服务器端读取,因此可以在Next.js中编写API代理路由,客户端请求该代理路由后,由服务器端读取Cookie并添加到请求头,再转发给后端接口。
步骤:
- 创建代理API路由,比如
api/proxy/[...path]/route.ts:
import { NextResponse } from 'next/server'; import axios from 'axios'; // 处理GET请求,同理可扩展POST/PUT等方法 export async function GET(request: Request) { // 从请求中读取Http-only Cookie const authToken = request.cookies.get('auth_token')?.value; if (!authToken) { return NextResponse.json({ message: 'Unauthorized' }, { status: 401 }); } // 解析请求路径,拼接后端目标地址 const url = new URL(request.url); const targetPath = url.pathname.replace('/api/proxy/', ''); const targetUrl = `${process.env.NEXT_PUBLIC_AXIOS_BASE_DEV_URL}${targetPath}`; try { const response = await axios.get(targetUrl, { headers: { Authorization: `Bearer ${authToken}`, }, }); return NextResponse.json(response.data); } catch (error) { return NextResponse.json( { message: 'Request failed' }, { status: (error as any)?.response?.status || 500 } ); } }
- 修改RTK Query的baseQuery,指向代理路由:
import { fetchBaseQuery } from '@reduxjs/toolkit/query/react'; const baseQuery = fetchBaseQuery({ baseUrl: '/api/proxy/', }); export const authApi = createApi({ reducerPath: 'api/auth', baseQuery, endpoints: (build) => ({ fetchMe: build.query<OAuthResponse, void>({ query: () => ({ url: 'auth/me', method: 'GET', }), }), }), });
这种方式完全符合Http-only Cookie的安全设计,所有认证逻辑由服务器端处理,客户端无需接触令牌。
方案2:客户端直接请求后端(需配置CORS)
如果不想使用代理,只要后端配置了正确的CORS策略,浏览器会自动将Http-only Cookie随请求发送给后端,无需客户端手动读取。
步骤:
后端配置CORS,允许携带凭证:
以Node.js/Express为例,设置:const cors = require('cors'); app.use(cors({ credentials: true, origin: process.env.NEXT_PUBLIC_FRONTEND_URL // 替换为你的前端域名 }));配置RTK Query的baseQuery,开启凭证携带:
import { fetchBaseQuery } from '@reduxjs/toolkit/query/react'; const baseQuery = fetchBaseQuery({ baseUrl: process.env.NEXT_PUBLIC_AXIOS_BASE_DEV_URL, credentials: 'include', // 关键:让浏览器自动携带Cookie }); export const authApi = createApi({ reducerPath: 'api/auth', baseQuery, endpoints: (build) => ({ fetchMe: build.query<OAuthResponse, void>({ query: () => ({ url: 'auth/me', method: 'GET', }), }), }), });
- 修改后端逻辑,从请求Cookie中提取
auth_token(替代之前从Authorization头读取的逻辑)。
注意:该方式要求前后端域名匹配或CORS配置正确,且后端需支持从Cookie中获取令牌。
内容的提问来源于stack exchange,提问作者Dmitriy Tilik
相关产品推荐
相关产品推荐

