Next.js 13(App目录)结合Laravel Sanctum的认证及Token存储问题
解决思路:Next.js 13 + Laravel Sanctum 会话与Token管理
一、Token存储的两种实用方案
1. HttpOnly Cookie(优先选,贴合Sanctum设计)
Laravel Sanctum本身就是靠Cookie维护会话的,完全不用手动存Token,浏览器会自动处理。
操作要点:
- 后端配置:
打开config/cors.php,把supports_credentials设为true,allowed_origins添加你的Next.js域名(比如http://localhost:3000)。
打开config/sanctum.php,在stateful数组里加入Next.js域名。 - 前端请求必须带
credentials: 'include',示例:
const login = async (email, password) => { const res = await fetch('http://你的Laravel接口域名/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', // 关键,让浏览器自动携带Cookie body: JSON.stringify({ email, password }) }); const data = await res.json(); // 登录成功后,所有后续请求都加这个参数,不用管Token的事 };
这种方式最安全,HttpOnly Cookie没法被JS读取,能防XSS攻击。
2. LocalStorage(简单但风险高)
如果一定要手动存Token,让后端登录接口返回Bearer Token,前端存在LocalStorage里,之后请求时在Header里带上。
示例:
// 登录时存Token const login = async (email, password) => { const res = await fetch('http://你的Laravel接口域名/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password }) }); const { token } = await res.json(); localStorage.setItem('sanctum-token', token); }; // 后续请求带Token const fetchProducts = async () => { const token = localStorage.getItem('sanctum-token'); const res = await fetch('http://你的Laravel接口域名/products', { headers: { 'Authorization': `Bearer ${token}` } }); return res.json(); };
⚠️ 注意:LocalStorage容易被XSS攻击窃取Token,生产环境尽量不用。
二、NextAuth的适配方案
完全可以用NextAuth来管理登录流程,把Laravel Sanctum作为自定义数据源,NextAuth帮你处理会话状态、路由守卫这些琐事。
1. 用Credentials Provider对接
NextAuth的Credentials Provider允许你自定义登录逻辑,直接调用Laravel的登录接口,把Sanctum Token存在NextAuth的会话里。
操作步骤:
- 先装NextAuth:
npm install next-auth - 在
app/api/auth/[...nextauth]/route.js写配置:
import NextAuth from 'next-auth'; import CredentialsProvider from 'next-auth/providers/credentials'; export const authOptions = { providers: [ CredentialsProvider({ name: '账号密码登录', credentials: { email: { label: '邮箱', type: 'email' }, password: { label: '密码', type: 'password' } }, async authorize(credentials) { // 调用Laravel登录接口 const res = await fetch('http://你的Laravel接口域名/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: credentials.email, password: credentials.password }) }); const user = await res.json(); // 登录成功就返回用户信息和Token,NextAuth会存到会话里 if (res.ok && user.token) { return { ...user, token: user.token }; } return null; } }) ], session: { strategy: 'jwt', // 用JWT存会话,适配自定义Token }, callbacks: { async jwt({ token, user }) { // 登录时把Sanctum Token加到JWT里 if (user) { token.sanctumToken = user.token; } return token; }, async session({ session, token }) { // 把Token暴露给前端会话,方便请求用 session.user.sanctumToken = token.sanctumToken; return session; } } }; const handler = NextAuth(authOptions); export { handler as GET, handler as POST };
- 前端用
useSession拿Token,然后请求接口:
import { useSession } from 'next-auth/react'; const fetchOrders = async () => { const { data: session } = useSession(); if (!session) return []; const res = await fetch('http://你的Laravel接口域名/orders', { headers: { 'Authorization': `Bearer ${session.user.sanctumToken}` } }); return res.json(); };
2. 结合Sanctum Cookie和NextAuth
如果用Sanctum的Cookie方案,NextAuth可以用来做前端的状态管理(比如判断用户是否登录、路由拦截),实际API请求还是靠浏览器自动带Cookie。
这种情况下,authorize逻辑改成验证Cookie是否有效:
async authorize(credentials) { // 调用Laravel的用户信息接口,验证Cookie有效性 const res = await fetch('http://你的Laravel接口域名/api/user', { credentials: 'include' }); if (res.ok) { const user = await res.json(); return user; } return null; }
这样NextAuth负责前端的会话状态,后端还是用Sanctum的Cookie机制,两全其美。
三、关键注意事项
- 跨域配置必须正确:Laravel的CORS和Sanctum的stateful域名必须包含你的Next.js域名,否则Cookie传不过去。
- 用NextAuth的话,一定要在环境变量里设
NEXTAUTH_URL,指向你的Next.js域名。 - 生产环境必须用HTTPS,防止Token被明文劫持。
内容的提问来源于stack exchange,提问作者psudo
相关产品推荐
相关产品推荐

