Nest.js+Passport会话认证问题:浏览器未携带Session Cookie
我用Nest.js结合Passport实现用户会话认证,遇到以下问题:
调用/login接口时,Postman和浏览器均能接收Set-Cookie响应头,但后续请求受保护路由时,Postman可正常携带Cookie通过认证,浏览器却未携带该Cookie,服务器返回403 Forbidden。服务器端打印的session信息在浏览器和Postman中一致,但AuthenticatedGuard在Postman请求中返回true,浏览器请求返回false。
相关代码
main.ts(Nest.js后端配置)
async function bootstrap() { const app = await NestFactory.create(AppModule); app.use(cookieParser()); // session配置 app.use( session({ secret: 'keyboard', resave: false, saveUninitialized: false, cookie: { maxAge: 10 * 60 * 1000, httpOnly: true, sameSite: 'none', }, }), ); app.use(passport.initialize()); app.use(passport.session()); app.use((req, res, next) => { res.header('Access-Control-Expose-Headers', 'x-total-count'); next(); }); app.enableCors({ origin: ['http://127.0.0.1:3000','http://localhost:3000/'], credentials: true, }); await app.listen(3000); } bootstrap();
AuthenticatedGuard(认证守卫)
@Injectable() export class AuthenticatedGuard implements CanActivate { async canActivate(context: ExecutionContext) { const request = context.switchToHttp().getRequest(); console.log(request.session); return request.isAuthenticated(); } }
受保护路由
@UseGuards(AuthenticatedGuard) @Patch('edit/:id') edit( @Param('id') id: string, @Body() editedData: EditAgentDto, @Request() req, ) { console.log(editedData) if (id === req.user.id) { return this.agentService.editAgent(id, editedData); } }
登录守卫与接口
@Injectable() export class LocalAgentGuard extends AuthGuard('agent') { async canActivate(context: ExecutionContext) { const result = (await super.canActivate(context)) as boolean; const request = context.switchToHttp().getRequest(); await super.logIn(request); return result; } }
@UseGuards(LocalAgentGuard) @Post('login') login(@Request() req) { return req.user; }
前端Axios请求代码(dashboard.tsx)
const onSubmit = (data) => { return new Promise((resolve, reject) => { axios.patch(`http://localhost:3000/agents/edit/64bcc86e51ce7016ffb3d6c8`,data,{withCredentials: true}) .then((res) =>{ toast.success('your data has been saved') console.log(res) resolve(); }) .catch(() => { toast.error('something went wrong') console.log('error') reject() }); }) }
前端Vite配置
import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' export default defineConfig({ server:{ host:'localhost', port:3000, }, plugins: [react()], })
排查与修复方案
1. Cookie的SameSite与Secure配置问题
当sameSite: 'none'时,现代浏览器要求Cookie必须设置secure: true(仅在HTTPS环境下生效)。但你当前是开发环境(HTTP),设置SameSite=None会导致浏览器拒绝存储Cookie。
修改session的cookie配置,根据环境动态调整:
cookie: { maxAge: 10 * 60 * 1000, httpOnly: true, // 开发环境用lax/strict,生产HTTPS环境再用none+secure sameSite: process.env.NODE_ENV === 'production' ? 'none' : 'lax', secure: process.env.NODE_ENV === 'production', },
2. CORS Origin配置错误
你的CORS origin里http://localhost:3000/末尾多了斜杠,和前端实际的http://localhost:3000不匹配,浏览器会因origin不匹配拒绝携带Cookie。去掉斜杠:
app.enableCors({ origin: ['http://127.0.0.1:3000','http://localhost:3000'], credentials: true, });
3. 前端登录请求未携带withCredentials
登录请求也需要添加withCredentials: true,否则浏览器不会保存登录时的Set-Cookie:
// 示例登录请求 axios.post('http://localhost:3000/login', {username: 'xxx', password: 'xxx'}, { withCredentials: true })
4. 前后端端口冲突
你的前端Vite和后端Nest.js都监听3000端口,会导致端口抢占,实际只有一个服务能运行,引发跨域问题。修改前端端口为5173(Vite默认),并更新CORS origin:
- Vite配置修改:
export default defineConfig({ server:{ host:'localhost', port:5173, }, plugins: [react()], })
- 后端CORS origin添加
http://localhost:5173:
app.enableCors({ origin: ['http://127.0.0.1:3000','http://localhost:3000', 'http://localhost:5173'], credentials: true, });
内容的提问来源于stack exchange,提问作者Abel
相关产品推荐
相关产品推荐

