Flask+Next.js跨域Cookie丢失求助:access_token_cookie缺失
问题概述
Flask后端(端口5000)与Next.js前端(端口3000)交互时,出现"msg": "Missing cookie \"access_token_cookie\""错误:前端控制台打印document.cookie能看到所有令牌,但跳转至AdminDashboard请求/admin/dashboard接口时,后端提示Cookie未设置。
核心问题分析
前端侧问题
- 冗余的Cookie手动设置:Flask已通过
set_access_cookies接口返回时自动设置Cookie,前端手动用js-cookie覆盖会导致Cookie属性(如SameSite、HttpOnly)不一致,跨域时无法正常携带。 - 跨域请求凭证配置错误:AdminDashboard中
credentials设为same-origin,但前后端不同端口属于跨域场景,需改为include才能携带Cookie。 - Cookie获取时机错误:在组件外部提前获取Cookie,Next.js服务端渲染时无浏览器Cookie,导致
csrf和access_token值为undefined。
后端侧问题
- 跨域头配置违规:
Access-Control-Allow-Origin设为*,但带Cookie的跨域请求不能用通配符,必须指定具体前端域名。 - Flask-JWT-Extended Cookie属性缺失:未配置跨域所需的
SameSite=None等属性,导致Cookie无法跨域传递。
具体修改方案
前端代码修改
1. 移除登录逻辑中的手动Cookie设置
删除登录成功后手动设置Cookie的代码,保留Flask返回的Cookie即可:
// 删除以下代码 Cookies.set("access_token_cookie", access_token); Cookies.set("refresh_token_cookie", refresh_token); Cookies.set("access_csrf_token_cookie", access_csrf_token);
2. 修正AdminDashboard请求配置
将跨域凭证改为include,并在useEffect内部获取Cookie:
import { useState, useEffect } from "react"; import Cookies from "js-cookie"; const AdminDashboard = () => { const [data, setData] = useState(); useEffect(() => { const dataFetch = async () => { const csrf = Cookies.get("access_csrf_token_cookie"); const response = await fetch("http://127.0.0.1:5000/admin/dashboard", { method: "GET", headers: { "Content-Type": "application/json", "X-CSRF-TOKEN": csrf, }, credentials: "include", // 跨域携带Cookie必须设为include }); const responseData = await response.json(); setData(responseData); console.log(responseData); }; dataFetch(); }, []); return ( <> {/* 原有Head和结构保留 */} <main> <div>hello guys</div> {data && <pre>{JSON.stringify(data, null, 2)}</pre>} </main> </> ); }; export default AdminDashboard;
后端代码修改
1. 配置正确的跨域头
推荐使用flask-cors统一管理跨域,避免手动设置出错:
from flask import Flask from flask_cors import CORS app = Flask(__name__) # 允许前端域名跨域,支持凭证传递 CORS(app, supports_credentials=True, origins=["http://localhost:3000"])
若手动设置跨域头,需替换接口中的通配符:
@admin_bp.route('/admin/dashboard', methods=["GET"]) @admin_required() def dashboard(): claim = get_jwt() current_user_id = get_jwt_identity() user = User.query.get(current_user_id) resp = jsonify( { "Message": f"Got protected information for ADMIN USER {user.username}", "User": user.serialize(), "claim": claim } ) # 替换为具体前端域名,允许凭证传递 resp.headers.add('Access-Control-Allow-Origin', 'http://localhost:3000') resp.headers.add('Access-Control-Allow-Credentials', 'true') return resp, 200
2. 配置Flask-JWT-Extended的Cookie属性
在Flask配置中添加跨域Cookie所需的属性:
app.config['JWT_TOKEN_LOCATION'] = ['cookies'] app.config['JWT_ACCESS_COOKIE_NAME'] = 'access_token_cookie' app.config['JWT_REFRESH_COOKIE_NAME'] = 'refresh_token_cookie' # 跨域需设置SameSite=None,开发环境http下Secure设为False,生产环境https设为True app.config['JWT_ACCESS_COOKIE_SAMESITE'] = 'NONE' app.config['JWT_ACCESS_COOKIE_SECURE'] = False app.config['JWT_REFRESH_COOKIE_SAMESITE'] = 'NONE' app.config['JWT_REFRESH_COOKIE_SECURE'] = False # 开启CSRF保护 app.config['JWT_COOKIE_CSRF_PROTECT'] = True
3. 登录接口添加跨域头
登录接口同样需要允许跨域凭证传递:
@auth_bp.route("/auth/login", methods=["POST"]) def login(): # 原有登录逻辑保留 resp = jsonify(...) set_access_cookies(resp, access_token) set_refresh_cookies(resp, refresh_token) # 添加跨域头 resp.headers.add('Access-Control-Allow-Origin', 'http://localhost:3000') resp.headers.add('Access-Control-Allow-Credentials', 'true') return resp, 200
验证步骤
- 重启Flask和Next.js服务
- 登录后,在浏览器开发者工具
Application -> Cookies中查看http://127.0.0.1:5000下的Cookie是否存在,且属性符合配置 - 访问AdminDashboard,查看请求头中是否携带
access_token_cookie
内容的提问来源于stack exchange,提问作者CornOnTheCob
相关产品推荐
相关产品推荐

