Nest后端Session认证与Next.js前端集成:Cookie无法保存问题求助
问题
已实现基于Session的Nest后端认证,使用Insomnia发起请求时可正常保存Session Cookie,但在Next.js前端发起登录请求时,Cookie无法在前端存储。不过登录后Redis数据库中已生成对应的Session ID。查阅NextAuth相关资料,未找到适配该场景的解决方案。
关键现象:
- 使用Insomnia发起请求可正常保存Session Cookie;
- 前端登录后,Redis数据库中已存在Session ID,但前端无Cookie存储。
相关代码如下:
前端AuthContext代码
import { createContext } from 'react'; type AuthContextType = { isAuthenticated: boolean; signIn: ({ email, password }: { email: string, password: string }) => Promise<void>; }; export const AuthContext = createContext({} as AuthContextType); export function AuthProvider({ children }: { children: React.ReactNode }) { const isAuthenticated = false; async function signIn({ email, password }: { email: string, password: string }): Promise<void> { //fazer request para minha api backend que vai retornar um session cookie const response = await fetch('http://localhost:3000/auth/login', { method: 'POST', body: JSON.stringify({ email, password }), headers: { 'Content-Type': 'application/json' } }) console.log(response.json()); } return ( <AuthContext.Provider value={{ isAuthenticated, signIn }}> {children} </AuthContext.Provider> ); }
前端登录页面代码
import { useState, useContext } from 'react'; import { useRouter } from 'next/router'; import { AuthContext } from '../contexts/AuthContext'; function LoginPage() { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const { signIn } = useContext(AuthContext); const Router = useRouter(); const handleLogin = async (event: React.FormEvent) => { event.preventDefault(); const data = { email: email, password: password }; try { await signIn(data); Router.push('/dashboard'); } catch (err) { console.log(err); } }; return ( <form onSubmit={handleLogin}> <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email" required /> <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="Password" required /> <button type="submit">Login</button> </form> ); } export default LoginPage;
后端app.js代码
async function bootstrap() { const app = await NestFactory.create(AppModule, { cors: true }); const PORT = Number(process.env.SERVER_PORT) || 3000; const client = redis.createClient({ url: process.env.REDIS_URL }); const RedisStore = connectRedis(session); app.use( session({ name: 'session', secret: process.env.SESSION_SECRET, resave: false, saveUninitialized: false, store: new RedisStore({ client, ttl: 86400, }), cookie: { maxAge: 24 * 60 * 60 * 1000, }, }), ); app.use(passport.initialize()); app.use(passport.session()); await app.listen(PORT, () => console.log(`Server started on port ${PORT}`)); }
问题根源
- 前端Fetch请求默认不携带/保存Cookie,需显式开启凭证配置;
- 后端仅设置
cors: true会导致Origin为*,与凭证传递规则冲突,无法正常下发Cookie; - Session Cookie的
sameSite、secure参数未适配跨域场景,导致浏览器拒绝存储。
解决方案
1. 前端修改:配置Fetch凭证选项
在AuthContext的signIn函数中添加credentials: 'include',允许跨域请求携带并保存Cookie:
async function signIn({ email, password }: { email: string, password: string }): Promise<void> { const response = await fetch('http://localhost:3000/auth/login', { method: 'POST', body: JSON.stringify({ email, password }), headers: { 'Content-Type': 'application/json' }, // 关键:开启凭证携带,允许跨域保存Cookie credentials: 'include' }); if (!response.ok) { throw new Error('登录失败'); } const result = await response.json(); console.log(result); }
2. 后端修改:完善CORS与Session配置
2.1 配置精准CORS规则
替换原有的cors: true,指定前端Origin并允许凭证传递:
async function bootstrap() { const app = await NestFactory.create(AppModule); const PORT = Number(process.env.SERVER_PORT) || 3000; const client = redis.createClient({ url: process.env.REDIS_URL }); // 配置CORS,替换为你的Next.js前端地址 app.enableCors({ origin: 'http://localhost:3001', credentials: true, allowedHeaders: ['Content-Type', 'Authorization'], methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'] }); const RedisStore = connectRedis(session); app.use( session({ name: 'session', secret: process.env.SESSION_SECRET, resave: false, saveUninitialized: false, store: new RedisStore({ client, ttl: 86400, }), cookie: { maxAge: 24 * 60 * 60 * 1000, httpOnly: true, // 防止XSS攻击,推荐开启 sameSite: process.env.NODE_ENV === 'production' ? 'none' : 'lax', secure: process.env.NODE_ENV === 'production', // 生产环境需开启HTTPS }, }), ); app.use(passport.initialize()); app.use(passport.session()); await app.listen(PORT, () => console.log(`Server started on port ${PORT}`)); }
参数说明
origin:必须指定前端具体地址,不能用*(否则credentials: true会失效);sameSite:开发环境用lax,生产跨域部署时设为none;secure:生产环境开启HTTPS时设为true,确保Cookie仅在HTTPS下传递。
3. 验证步骤
- 重启Nest后端与Next.js前端;
- 发起登录请求,查看浏览器控制台
Application -> Cookies,确认sessionCookie已存在; - 后续请求需保持
credentials: 'include'配置,确保携带Session Cookie。
补充:Next.js代理方案(可选)
若不想处理跨域,可在next.config.js中配置反向代理:
module.exports = { async rewrites() { return [ { source: '/api/auth/:path*', destination: 'http://localhost:3000/auth/:path*', }, ]; }, };
此时前端请求改为/api/auth/login,Fetch的credentials可改为'same-origin'。
内容的提问来源于stack exchange,提问作者Edson Magno
相关产品推荐
相关产品推荐

